home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / AHDI / TTDRIVER / DRIVER.S < prev    next >
Encoding:
Text File  |  2001-02-09  |  67.4 KB  |  2,175 lines

  1. ; Apr 10 1991 v4.04a'
  2.  
  3. ;------------------------------------------------------------------------
  4. ;                                    :
  5. ;    AHDI Hard Disk Driver for the Atari ST and TT            :
  6. ;    Copyright 1985,1986,1987,1988,1989,1990,1991 Atari Corp.    :
  7. ;    All Rights Reserved                        :
  8. ;                                    :
  9. ;------------------------------------------------------------------------
  10.  
  11.  
  12. ;+
  13. ; Conditional Assembly Switches
  14. ;-
  15. ospool        equ    1        ; increase size of OS pool for ROM
  16.  
  17.  
  18. ;
  19. ;+
  20. ; Edit History
  21. ;
  22. ;
  23. ; 22-May-1989    ml    Started this from ahdi 3.00
  24. ;            Files created for this driver:
  25. ;            ACSI.S        Low-level driver for ACSI.
  26. ;            CMDBLK.S    Builds packets for command blocks.
  27. ;            DOIT.S        Sends packets out to SCSI or ACSI.
  28. ;            DRIVER.S    This file.
  29. ;            SCSI.S        Low-level driver for SCSI.
  30. ;
  31. ; 25-May-1989    ml    Eliminated pread(), use _ahdi_rw() in physical mode
  32. ;            instead.
  33. ;
  34. ; 06-Jun-1989    ml    Created INSTALL.S for driver installation.
  35. ;
  36. ; 11-Jul-1989    ml    Rwabs() now handles DMA to fast RAM on ACSI side
  37. ;            also.  If no extra RAM was reserved for fast RAM
  38. ;            transferred, _dskbufp is used for the transfer.
  39. ;            (This is going to be really slow!!!)
  40. ;
  41. ; 19-Jul-1989    ml    If there is cache on CPU, Rwabs() reads will
  42. ;            flush both the I and D cache.
  43. ;
  44. ; 06-Sept-1989    ml    Use _FRB (in the cookie jar) for fast RAM transfer,
  45. ;            assuming _FRB WILL be there if there is fast RAM on
  46. ;            the machine.
  47. ;
  48. ; 20-Feb-1990    ml 3.64    Fixed bug in return code when doing ACSI odd transfer.
  49. ;            When successful, 0 should be returned.
  50. ;
  51. ; 02-Mar-1990    ml 3.65    Took out wait loop for SCSI 0 to be ready.
  52. ;            (In install.s)
  53. ;
  54. ; 05-Mar-1990    ml 3.66    Added more checks for I/O to ACSI and SCSI non-
  55. ;            accessible memory.  _FRB will be used if it exists.
  56. ;            If _FRB doesn't exist, _dskbuf will used (which
  57. ;            means I/O could be "really" slow).  (_do_rw())
  58. ;
  59. ;            _FRB is being looked for when it's needed for the
  60. ;            first time, not at boot time.  (Applications can
  61. ;            add the _FRB when they are executed.)
  62. ;
  63. ; 08-Mar-1990    ml    Added SCFRDMA flag in defs.h to make SCSI DMA to 
  64. ;            fast RAM conditional assembly.
  65. ;            (driver.s modified)
  66. ;
  67. ; 15-Mar-1990    ml    Added DEBUG flag in defs.h to make debugging code
  68. ;            conditional assembly.
  69. ;
  70. ; 09-Apr-1990    ml 3.67    Added a "read" from WDL after toggling the ACSI DMA
  71. ;            chip to point the MMU to the correct direction.
  72. ;            (acsi.s modified)
  73. ;
  74. ; 10-Apr-1990    ml    Put up banner at beginning and end of loading driver
  75. ;            (requested by jwt), instead of just at the end.
  76. ;            (Printing of banner moved to install.s)
  77. ;
  78. ; 17-Apr-1990    ml    Added ODMA flag in defs.h to make the klutch of 
  79. ;            making byte counter bigger than # bytes requested
  80. ;            when receiving data from SCSI conditional assembly.
  81. ;            (scsi.s modified)
  82. ;
  83. ; 20-Apr-1990    ml    Added RDWDL flag in defs.h to make the "extra read"
  84. ;            added on 09-Apr-1990 conditional assembly.  (When
  85. ;            writing to ACSI, first 32 bytes are always FF's!!
  86. ;            Wondering why...)
  87. ;            (acsi.s modified)
  88. ;
  89. ; 30-Jul-1990    ml 4.00    Final for TT release. 
  90. ;            (Vectored-interrupts code not included)
  91. ;
  92. ; 31-Jul-1990    ml     Vectored-interrupt code included.
  93. ;
  94. ; 29-Oct-1990    ml 4.01    BUG!!!  Getcookie() module provided by AKP has a
  95. ;            variable declared in the bss.  This bss will be
  96. ;            clobbered when the driver adds GEMDOS buffers and
  97. ;            OS pool.  When getcookie() was called, and access 
  98. ;            the bss, it clobbered whatever was using its space
  99. ;            at the time.
  100. ;            Fixed in cookie.s by changing moving the variable
  101. ;            from the bss to the text segment.
  102. ;            (cookie.s modified)
  103. ;
  104. ; 26-Nov-1990    ml 4.02    BUG!!  From 3.00 through 4.01, when Rwabs() is called
  105. ;            in raw mode, it ignored media change completely.
  106. ;            This created problems with cartridge swapping on the 
  107. ;            removable drives.  If Getbpb(), on a logical drive 
  108. ;            that has not been accessed on the previous cartridge,
  109. ;            is called right after a cartridge swap, Getbpb() will
  110. ;            call Rwabs() in raw mode to read the partition map of
  111. ;            the physical unit concerned.  This Rwabs() call will
  112. ;            get the media change error from the controller and 
  113. ;            ignores it without setting any mcflg of the physical
  114. ;            unit.  Now when Mediach(), on a logical drive that was
  115. ;            accessed on the previous cartridge, is called, the 
  116. ;            driver will return media not change!
  117. ;            In version 4.02, Rwabs() still does not return media
  118. ;            change error when called in raw mode, but will 
  119. ;            remember it  by setting the mcflgs of the physical 
  120. ;            unit concerned to maybe changed.
  121. ;
  122. ; 02-Apr-1991    ml 4.03    BUG!!  At boot time, 
  123. ;                move.l    #(i_sasi1-i_sasi),tokeep 
  124. ;            is used to find number of bytes of code to keep.  
  125. ;            In pre-4.00 AHDI, this works just fine because both 
  126. ;            i_sasi1 and i_sasi are in the same file.  But, since 
  127. ;            3.00, i_sasi1 has been moved to the file INSTALL.S, 
  128. ;            thus external.  Madmac did not complain that the 
  129. ;            expression #(i_sasi1-i_sasi) is not valid anymore.  
  130. ;            Instead it assembles the code as
  131. ;                move.l    #i_sasi1,tokeep
  132. ;            This is bad, because it depends of where the driver 
  133. ;            is being loaded, the driver may end up hogging large
  134. ;            amount of memory that it is not using.  This is now
  135. ;            fixed by calculating the amount at run time.
  136. ;                move.l    #i_sasi1,tokeep 
  137. ;                subi.l    #i_sasi,tokeep
  138. ;            (driver.s modified)
  139. ;
  140. ; 04-Apr-1991    ml    Some SCSI drives will recalibrate every so often.
  141. ;            While recalibrating, the drive still accepts the
  142. ;            command block, but delays the transfer of data to 
  143. ;            after the recalibration.  So, timeout for the data
  144. ;            transfer should include the amount of time spent 
  145. ;            on recalibration.  The worst case we know of is
  146. ;            the Fujisu drives which takes 4 seconds.  So, the 
  147. ;            default for recalibration time is set to 4 seconds.
  148. ;            (driver.s, scsi.s modified)
  149. ;
  150. ; 10-Apr-1991  ml 4.04a    Added in implementation of Arbitration on SCSI bus.
  151. ;            (scsi.s modified)
  152. ;            
  153. ;-
  154.  
  155.  
  156. .include    "defs.h"
  157. .include    "error.h"
  158. .include    "sysvar.h"
  159. .include    "68030.s"
  160. .include    "mfp.h"
  161. .include    "scsi.h"
  162.  
  163.  
  164. .extern _untrdy
  165. .extern _rqsense
  166. .extern _hread
  167. .extern _hwrite
  168. .extern _xtdread
  169. .extern _xtdwrt
  170.  
  171. .extern    i_sasi1
  172. .extern    _getcookie
  173.  
  174. ;
  175. ;+
  176. ; Entry points:
  177. ;
  178. ;    +0   GEMDOS entry point (double-click, or \AUTO folder on floppy)
  179. ;    +4   Boot entry point (from driver file off of C:)
  180. ;    +8   Reserved for future use
  181. ;    +$C  $F0AD magic number
  182. ;    +$E  version number
  183. ;    +$12 # chunks of ospool to add
  184. ;    +$14 # of sqnpart entries that follows
  185. ;    +$16 first sqnpart entry
  186. ;
  187. ; if bootloaded, d0 = # bytes allocated by boot code.
  188. ;-
  189. i_sasi:    bra    gboot            ; GEMDOS entry-point
  190.     bra    iboot            ; Boot entry-point
  191.     bra    iboot            ; (unused, reserved)
  192.  
  193.  
  194. ;+
  195. ;  Patchable variables
  196. ;-
  197. magicnum:    dc.w    $f0ad        ; wasn't here in previous releases
  198. vernum:        dc.w    $0404        ; version number
  199. numchunks:    dc.w    128        ; # chunks of ospool to add
  200.         .globl    defbigsect
  201. defbigsect:    dc.w    512        ; default size of a big sector
  202. numsqnpart:    dc.w    MAXACSI        ; number of sqnpart entries to follow
  203.         .globl    defsqnpart
  204. defsqnpart:    dcb.b    MAXACSI,1    ; default # drives for rmvbl ACSI unit
  205.  
  206. ; They're NEW!! Introduced in this version:
  207. numsqcnpart:    dc.w    MAXSCSI        ; number of sqcnpart entries to follow
  208.         .globl    defsqcnpart
  209. defsqcnpart:    dcb.b    MAXSCSI,1    ; default # drives for rmvbl SCSI unit
  210.         .globl    scxltmout    
  211. scxltmout:    dc.l    12001        ; SCSI long-timeout (>1 min)
  212.         .globl    slwsclto    
  213. slwsclto:    dc.l    5000        ; SCSI stunit() long-timeout (>25s)
  214.         .globl    slwscsto    
  215. slwscsto:    dc.l    42        ; SCSI stunit() short-timeout (>205ms)
  216.         .globl    scltmout    
  217. scltmout:    dc.l    201        ; SCSI long-timeout (>1000 ms)
  218.         .globl    scstmout    
  219. scstmout:    dc.l    101        ; SCSI short-timeout (>500 ms)
  220.         .globl    rcaltm    
  221. rcaltm:        dc.l    801        ; time for drive recalibration (>4s)
  222.         .globl    scsiid
  223. scsiid:        dc.b    6        ; SCSI host ID
  224. .even
  225.  
  226.  
  227. ;+
  228. ; GEMDOS entry;
  229. ;   find amount of memory availble and store in d0.l
  230. ;-
  231. gboot:    movea.l    4(sp),a2        ; a2 -> basepage
  232.     move.l    4(a2),d0        ; d0 = available memory
  233.     sub.l    (a2),d0            ;    = p_hitpa - p_lowtpa - basepage
  234.     sub.l    #$0100,d0
  235.     bra    i_sasi1            ; (continue with normal initialization)
  236.  
  237.  
  238. ;+
  239. ;  Boot entry;
  240. ;    set "bootloaded", record base address from boot loader, 
  241. ;    and continue with normal boot process.
  242. ;-
  243. iboot:    st    bootloaded        ; boot entry-point, set flag
  244.     sub.l    #$1c,d0            ; memory available -= file header
  245.     move.l    a2,baseaddr        ; install base address
  246.                     ; a2 = beginning addr of this block
  247.     bra    i_sasi1            ; (continue with normal initialization)
  248.  
  249.  
  250. ;
  251. ;+
  252. ; Driver State
  253. ;-
  254.         dc.b    13,'AHDI : Apr 10 1991 v4.04a'
  255.         dc.b    13,10,$bd,'Atari Corp.'
  256.         dc.b    ' 1985, 1986, 1987, 1988, 1989, 1990, 1991'
  257.         dc.b    13,10,0,$1A
  258. .even
  259.  
  260. ;*****  Beginning Of Published Variables  *****
  261.  
  262.         .globl    puns
  263. puns:        dc.w    0        ; # of physical units on user's system
  264.  
  265. dummy1:        dcb.b    2,-1        ; dummy pun entries for A and B
  266.         .globl    pun
  267. pun:        dcb.b    MAXUNITS,0    ; physical unit table
  268. .even
  269.  
  270. dummy2:        dcb.l    2,0        ; dummy start entries for A and B
  271.         .globl    start
  272. start:        dcb.l    MAXUNITS,0    ; partition start table
  273.  
  274.         .globl    cookie        ; *** DON'T CHANGE ***
  275. cookie:        dc.l    $41484449    ; cookie = 'AHDI'
  276.  
  277.         .globl    cookptr
  278. cookptr:    dc.l    0        ; pointer to cookie
  279.  
  280. versn:        dc.w    $0404        ; version number: MMmm
  281.  
  282.         .globl    maxssz
  283. maxssz:        dc.w    512        ; maximum sector size allowed
  284.  
  285. spndown:    dc.l    0        ; time limit to spin down unit 0
  286.                     ; applicable to Stacy ONLY
  287.  
  288.         .globl    numacsi
  289. numacsi:    dc.w    0        ; number of ACSI drives
  290.  
  291.         dcb.w    29,0        ; reserved for future use
  292.  
  293. ;*****  End Of Published Variables  *****
  294.  
  295.     .globl    mcflgs
  296. mcflgs:    dcb.b    MAXUNITS,2        ; media change flag table
  297.     .globl    xst
  298. xst:    dcb.b    MAXUNITS,1        ; drive existence flag table
  299. bpbs:    dcb.b    BPBLEN,0        ; a bpb 
  300. serno:    dcb.b    MAXUNITS*SERLEN,0    ; serial number table
  301.     .globl    sratio
  302. sratio:    dcb.b    MAXUNITS,1        ; log sect size : phys sect size tbl
  303. fatsum:    dcb.b    MAXUNITS*FATLEN,0    ; FAT checksum table
  304. fatst:    dcb.w    MAXUNITS,0        ; starting sector # of last FAT
  305. fatend:    dcb.w    MAXUNITS,0        ; ending sector # of last FAT
  306.  
  307.         .globl    bootloaded
  308. bootloaded:    dc.w    0        ; nonzero if loaded from boot sector
  309.         .globl    memalloc
  310. memalloc:    dc.l    0        ; total memory available if bootloaded
  311. baseaddr:    dc.l    0        ; -> base addr of .PRG file
  312. tokeep:        dc.l    0        ; amount memory to keep
  313.  
  314.         .globl    cpun
  315. cpun:        dc.w    0        ; current physical unit
  316.         .globl    npart
  317. npart:        dc.w    0        ; number of partitions found
  318. bfat:        dc.w    0        ; 0: 12-bit FAT; 1: 16-bit FAT
  319.  
  320. strec:        dc.l    0        ; starting sector to read/write
  321. endrec:        dc.l    0        ; last sector to read/write
  322. stbuf:        dc.l    0        ; starting address of buffer
  323.         .globl    embscsi
  324. embscsi:    dc.b    0        ; 1: embedded SCSI drive
  325.  
  326. frbbuf:        dc.l    0        ; pointer to _FRB
  327.  
  328. _retries:    dc.w    NRETRIES    ; number of retries to do
  329. retrycnt:    dc.w    1        ; retry counter
  330.  
  331.         .globl    o_bpb
  332. o_bpb:        dc.l    1        ; old bpb vector
  333.         .globl    o_rw
  334. o_rw:        dc.l    1        ; old rwabs vector
  335.         .globl    o_mediach
  336. o_mediach:    dc.l    1        ; old media change vector
  337.  
  338.         .globl    sendata
  339. sendata:    dcb.b    32,0        ; buffer for sense data
  340.  
  341. lastmdctm:    dc.l    0        ; time media change was last called
  342.         .globl    pbuf
  343. pbuf:        dc.l    0        ; ptr to start of root sector image
  344. fsiz:        dc.w    0        ; FAT size in sectors
  345. fatrec:        dc.w    0        ; 2nd FAT starting sector
  346.         .globl    sizr
  347. sizr:        dc.w    1        ; ratio of log : phys sector size
  348. cstart:        dc.l    0        ; current dev's starting sector
  349. temp:        dc.l    0        ; temporary storage
  350.         .globl    savssp
  351. savssp:        dc.l    1        ; (saved SSP)
  352.         .globl    _cachexst
  353. _cachexst:    dc.b    0        ; 0: no cache    1: with cache
  354.         .globl    ext
  355. ext:        dc.b    0        ; if =0, not processing ext partition
  356.         .globl    extrt
  357. extrt:        dc.l    0        ; starting sector of ext DOS partition
  358.         .globl    extvol
  359. extvol:        dc.l    0        ; offset wrt ext DOS partition
  360. pbpb:        dc.w    0        ; partition # for dev
  361. .even
  362.  
  363.  
  364. ;
  365. ;+
  366. ; Front End
  367. ;-
  368.  
  369. ;+
  370. ;  Return pointer to BPB (or NULL)
  371. ;
  372. ;    Synopsis:    LONG hbpb(dev)
  373. ;        WORD dev;    4(sp).w
  374. ;-
  375.     .globl    hbpb
  376. hbpb:    move.w    4(sp),d0        ; d0 = devno
  377.     clr    d1            ; d1 = 0, physical op not possible
  378.     movea.l    o_bpb,a0        ; a0 -> pass-through vector
  379.     lea    _sasi_bpb(pc),a1    ; a1 -> our handler
  380.     bra.s    check_dev        ; do it
  381.  
  382.  
  383. ;+
  384. ;  Read or write logical sectors
  385. ;
  386. ;    Synopsis:    LONG hrw(rw, buf, count, recno, dev)
  387. ;        WORD rw;    $4(sp).w
  388. ;        char *buf;    $6(sp).l
  389. ;        WORD count;    $a(sp).w
  390. ;        WORD recno;    $c(sp).w
  391. ;        WORD dev;    $e(sp).w
  392. ;-
  393.     .globl    hrw
  394. hrw:    move.w    $e(sp),d0        ; d0 = devno
  395.     move.w    4(sp),d1        ; d1 includes physical device flag
  396.     movea.l    o_rw,a0            ; a0 -> pass-through vector
  397.     lea    _sasi_rw(pc),a1        ; a1 -> our handler
  398.     bra.s    check_dev        ; do it
  399.  
  400.  
  401. ;+
  402. ;  Check for media change
  403. ;
  404. ;    Synopsis:    LONG hmediach(dev)
  405. ;        WORD dev;    4(sp).w
  406. ;-
  407.     .globl    hmediach
  408. hmediach:
  409.     move.w    4(sp),d0        ; d0 = devno
  410.     clr    d1            ; physical operation not possible
  411.     movea.l    o_mediach,a0        ; a0 -> pass-through vector
  412.     lea    _sasi_mediach(pc),a1    ; a1 -> our handler
  413.  
  414.  
  415. ;+
  416. ;  check_dev - use handler, or pass vector through
  417. ;
  418. ;  Passed:    d0.w = device#
  419. ;        d1, bit 3  1=physical operation
  420. ;        a0 ->  old handler
  421. ;        a1 ->  new handler
  422. ;        a5 ->  $0000 (zero-page ptr)
  423. ;
  424. ;  Jumps-to:    (a1) if dev in range for this handler
  425. ;        (a0) otherwise
  426. ;-
  427. check_dev:
  428.     subq    #2,d0            ; lowest device is 2 (unit 0 or C:)
  429.     bmi.s    chkd_f            ; if lower, not one of ours
  430.  
  431.     btst    #3,d1            ; is this a physical unit operation?
  432.     beq.s    chkd_a            ; if not set, go to chkd_a
  433.  
  434.     cmp.w    numacsi,d0        ; a valid ACSI unit?
  435.     blt.s    chkd_s            ; if so, it's one of ours
  436.  
  437.     sub.w    #MAXACSI,d0        ; a SCSI unit number?
  438.     bmi.s    chkd_f            ; if lower, not one of ours
  439.  
  440.     move.w    puns,d1            ; d1.w = number of valid SCSI units
  441.     sub.w    numacsi,d1        ;      = total num - num ACSI
  442.     cmp.w    d1,d0            ; a valid SCSI unit?
  443.     bge.s    chkd_f            ; if higher, not one of ours
  444.     bra.s    chkd_s            ; else it IS one of of ours
  445.  
  446. chkd_a:    lea    pun,a2            ; pointer to pun map
  447.     tst.b    0(a2,d0.w)        ; must be positive for a real unit
  448.     bmi.s    chkd_f
  449. chkd_s:    movea.l    a1,a0            ; yes -- follow success vector
  450. chkd_f:    jmp    (a0)            ; do it
  451.  
  452.  
  453. ;
  454. ;+
  455. ; Medium-Level Driver
  456. ;-
  457.  
  458. ;+
  459. ; Return BPB for logical device
  460. ;
  461. ; Synopsis:    LONG _sasi_bpb(dev)
  462. ;        WORD dev;    $4(sp).w
  463. ;
  464. ; Returns:    NULL, or a pointer to the BPB buffer
  465. ;
  466. ; 10-21-88    ml.    I am not making a special case for non-removable
  467. ;            hard disk, because if a program uses Allan's
  468. ;            program to force a media change, the program 
  469. ;            should be getting the "Real" AND "New" BPB.
  470. ;            (The old (v1.7 and before) AHDI only index into
  471. ;            the bpbs table and return the pointer, without
  472. ;            actually go and read the boot sector of the dev.)
  473. ;-
  474. _sasi_bpb:
  475.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  476.     move.w    4(sp),d1        ; d1 = device number
  477.     lea    pun,a0            ; a0 -> pun table
  478.     adda.w    d1,a0            ; a0 -> pun @ dev's entry
  479.     moveq    #0,d2            ; coerce byte to word
  480.     move.b    (a0),d2            ; d2.w = pun that dev belongs to
  481.     move.w    d2,cpun            ; cpun = pun(dev)
  482.  
  483.     lea    xst,a1            ; a1 -> drive existence table
  484.     tst.b    (a1,d1.w)        ; does drive exist?
  485.     bne.s    bpbgo            ; if it does, go on normally
  486.                     ; else, see if it really doesn't exist
  487.     movem.l    d1/a0,-(sp)        ; save registers
  488.     move.w    d2,-(sp)        ; physical unit number
  489.     bsr    _untrdy            ; verify by doing test unit ready
  490.     addq.l    #2,sp            ; cleanup stack
  491.     movem.l    (sp)+,d1/a0        ; restore registers
  492.     tst.w    d0            ; return good status?
  493.     beq    badbpb            ; if yes, ie. medium has not changed
  494.                     ; therefore, dev still doesn't exist
  495.     moveq    #1,d0            ; else medium may have changed
  496.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  497.                     ; and go try to get BPB
  498. bpbgo:    move.l    _dskbufp,pbuf        ; pbuf -> 2nd half of 1K disk buf
  499.     add.l    #512,pbuf
  500.  
  501. bpb00:    move.l    a0,-(sp)        ; save ptr to pun(dev)
  502.     move.w    cpun,-(sp)        ; physical unit number
  503.     addq.w    #2,(sp)            ; unit # including A: and B:
  504.     clr.w    -(sp)            ; from sector 0
  505.     move.w    #1,-(sp)        ; read in 1 sector
  506.     move.l    pbuf,-(sp)        ; buffer to read into
  507.     move.w    #$a,-(sp)        ; in phys mode/ignore media change
  508.     bsr    _ahdi_rw        ; ahdi_rw($a, pbuf, 1, 0, cpun)
  509.     adda    #12,sp
  510.     movea.l    (sp)+,a0        ; restore ptr to pun(dev)
  511.     tst    d0            ; read successful?
  512.     beq.s    bpb0            ; if yes, go on normally
  513.                     ; else call up error handler
  514. bpberr:    move.l    a0,-(sp)        ; save ptr to pun(dev)
  515.     move.w    8(sp),d1        ; a0 = drive # excluding A: and B:
  516.     bsr    critic            ; call up critical error handler
  517.     move.l    (sp)+,a0        ; restore ptr to pun(dev)
  518.     cmpi.l    #CRITRETRY,d0        ; retry?
  519.     beq.s    bpb00            ; if so, go and try again
  520.     bra    badbpb            ; else return no BPB
  521.  
  522. bpb0:    move.w    cpun,d2            ; d2 = physical unit number of dev
  523.     move.w    #0,pbpb            ; pbpb = partition # dev corresponds
  524. bpb1:    cmp.b    -(a0),d2        ; pun that dev belongs to == (a0)?
  525.     bne.s    bpb2
  526.     addq.w    #1,pbpb
  527.     bra.s    bpb1
  528.  
  529. bpb2:    move.w    #MAXNPART,d1        ; do #MAXNPART times
  530.     movea.l    pbuf,a0            ; a0 -> beginning of root sector
  531.     cmpi.w    #SIG,DOSSIG(a0)        ; is root sector in DOS format?
  532.     bne.s    bpb3            ; if not, assume it's in GEMDOS format
  533.     bsr    dosbpb            ; else, handle it the DOS way
  534.     bra.s    bpb4            ; else, go get the bpb
  535. bpb3:    move.w    #1,bfat            ; 16 bit FAT always for GEMDOS
  536.     bsr    gembpb            ; handle it the GEMDOS way
  537. bpb4:    tst.w    d0            ; successful?
  538.     beq.s    bpbnf            ; if =0, no valid BPB found
  539.     bpl.s    bpb5            ; if +ive, valid BPB found
  540.     bra.s    badbpb            ; else no BPB found
  541.                     ; partition not found
  542. bpbnf:    lea    xst,a0            ; a0 -> drive existence table
  543.     move.w    4(sp),d0        ; d0 = dev number
  544.     clr.b    (a0,d0.w)        ; dev definitely does not exist
  545.     lea    mcflgs,a0        ; a0 -> mcflgs table
  546.     move.b    #2,(a0,d0.w)        ; set as medium has changed
  547.     bra.s    badbpb            ; can't find such a partition
  548.  
  549. bpb5:    move.l    d1,-(sp)        ; start_sector
  550.     move.w    8(sp),-(sp)        ; dev number
  551.     bsr    getbpb            ; getbpb(dev, start_sector)
  552.     addq.l    #6,sp            ; clean up stack
  553.     tst.l    d0            ; getbpb successful?
  554.     bpl.s    retbpb            ; if so, return ptr to bpb
  555. badbpb:    moveq    #0,d0            ; return no bpb found
  556. retbpb:    rts
  557.  
  558.  
  559. ;
  560. ;+
  561. ; dosbpb - find the DOS partition that corresponds to the requested
  562. ;       logical drive
  563. ; Passed:
  564. ;    a0 = buffer address for root sector
  565. ;    d1 = number of entries in partition map
  566. ;
  567. ; Assumed:
  568. ;    pbpbs = partition being looked for
  569. ;
  570. ; Returns:
  571. ;    d0.b = 0        if partition not found
  572. ;         = negative #    some kind of error
  573. ;         = positive #    system indicator of the partition
  574. ;    d1.l = starting sector of the partition (if it is found)
  575. ;-
  576. dosbpb:    adda.w    #DOSPM,a0        ; a0 -> partition map
  577. dbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  578.     sf    ext            ; not dealing with ext partition
  579.     bsr    fdpart            ; find a partition
  580.     tst.b    d0            ; found any?
  581.     beq.s    dbpba            ; not a valid partition
  582.     cmpi.b    #5,d0            ; extended partition?
  583.     bne.s    dbpb1            ; if not, it's a regular partition
  584.     st    ext            ; else, it's an extended partition
  585.     move.l    #0,extvol        ; offset from start of partition = 0
  586.     move.l    d1,extrt        ; starting sector # of ext partition
  587. dbpbx:    bsr    fdnxt            ; find next logical drive
  588.     tst.b    d0            ; found any?
  589.     beq.s    dbpba            ; no logical drive found
  590.     bmi.s    dbpb2            ; error returned
  591.     cmpi.b    #5,d0            ; extended volume?
  592.     beq.s    dbpbx            ; if so, go find next logical drive
  593. dbpb1:    subq.w    #1,pbpb            ; partition that we want?
  594.     bpl.s    dbpb3            ; if not, continue the search
  595. dbpb2:    addq.l    #8,sp            ; else clean up stack
  596.     move.w    #0,bfat            ; assume partition has 12-bit fat
  597.     cmpi.b    #1,d0            ; 12-bit fat?
  598.     beq.s    dbpb22            ; if so, return
  599.     move.w    #1,bfat            ; else bflag = 1 for 16-bit fat
  600. dbpb22:    bra.s    dbpbr            ; and return
  601. dbpb3:    tst.b    ext            ; clun is in ext partition?
  602.     bne.s    dbpbx            ; if so, go find next ext vol
  603. dbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  604.     adda    #16,a0            ; index to next entry in pmap
  605.     dbra    d1,dbpb0
  606.     moveq    #0,d0            ; partition not found!
  607. dbpbr:    rts
  608.  
  609.     
  610. ;+
  611. ; fdpart - find a DOS partition.
  612. ;
  613. ; Passed:
  614. ;    a0 = address to partition entry
  615. ;
  616. ; Returns:
  617. ;    d0.b = 0        partition is not valid
  618. ;         = positive    #    partition is a valid partition
  619. ;           (this is the system indicator of the partition)
  620. ;    d1.l = starting sector # of a valid partition (if d0.b = 1 or 4)
  621. ;         = starting sector # of extended partition (if d0.b = 5)
  622. ;-
  623.     .globl    fdpart
  624. fdpart:    tst.l    12(a0)            ; partition's size?
  625.     beq.s    fdp0            ; if =0, not valid
  626.  
  627.     move.b    4(a0),d0        ; d0 = system indicator
  628.     beq.s    fdpr            ; if =0, not valid
  629.  
  630.     cmpi.b    #4,d0            ; if =4, valid
  631.     beq.s    fdp1
  632.  
  633.     cmpi.b    #1,d0            ; if =1, valid
  634.     beq.s    fdp1
  635.  
  636.     cmpi.b    #5,d0            ; if =5, valid
  637.     beq.s    fdp1
  638.  
  639. fdp0:    moveq    #0,d0            ; else, not valid
  640.     bra.s    fdpr
  641.  
  642. fdp1:    move.l    8(a0),d1        ; d1.l = swapped starting sector #
  643.     ror.w    #8,d1            ; swap hi and lo byte of high word
  644.     swap    d1            ; swap hi and lo word
  645.     ror.w    #8,d1            ; swap hi and lo byte of low word
  646. fdpr:    rts
  647.  
  648.  
  649. ;+
  650. ; fdnxt - find a logical drive in the extended DOS partition
  651. ;
  652. ; Passed:
  653. ;    d0.b = (= 5 if a new extended volume was found)
  654. ;           (= 0 if nxtdrv was successful for last logical drive found)
  655. ;    d1.l = starting sector # of this extended volume
  656. ;    d2.b = count down for logical drive entries (if d0.b != 5)
  657. ;    a0.l = address of partition entry to be checked (if d0.b != 5)
  658. ;
  659. ; Assumes:
  660. ;    cpun = current physical unit #
  661. ;    extrt = starting sector # of extended DOS partition
  662. ;    extvol = offset from start of extended DOS partition (in sectors)
  663. ;
  664. ; Returns:
  665. ;    d0.b = 0        no logical drive found
  666. ;         = positive #    valid logical drive found
  667. ;           (this is the system indicator of the logical drive)
  668. ;         = negative #    error occured
  669. ;    d1.l = starting sector # of the logical drive (if d0.b = 1 or 4)
  670. ;         = starting sector # of next extended volume (if d0.b = 5)
  671. ;-
  672.     .globl    fdnxt
  673. fdnxt:    cmpi.b    #5,d0        ; new extended volume found?
  674.     bne.s    fdnxt0        ; if not, search for one
  675.     move.l    d1,-(sp)    ; from beginning of extended volume
  676.     move.w    cpun,-(sp)    ; physical unit number
  677.     addq.w    #2,(sp)        ; unit # including A: and B:
  678.     move.w    #-1,-(sp)    ; using a long sector number
  679.     move.w    #1,-(sp)    ; read in 1 sector
  680.     move.l    _dskbufp,-(sp)    ; buffer to read into
  681.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  682.     bsr    _ahdi_rw    ; ahdi_rw($a, buf, 1, -1, cpun, lsectno)
  683.     adda    #16,sp        ; cleanup stack
  684.     tst.w    d0        ; read successful?
  685.     bne    fdnxtr        ; if not, return
  686.     
  687.     movea.l    _dskbufp,a0    ; else, 
  688.     cmpi.w    #SIG,DOSSIG(a0)    ; boot record valid?
  689.     bne.s    fdnxtr        ; if not, return no drive found
  690.                 ; (d0 already set by ahdi_rw)
  691.     adda.w    #DOSPM-16,a0    ; a0 -> 1st entry in log drive map
  692.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  693.  
  694. fdnxt0:    subq.w    #1,d2        ; more entries to search?
  695.     bmi.s    fdnxt1        ; if not, return
  696.  
  697.     adda    #16,a0        ; a0 -> entry to be examined
  698.     tst.l    12(a0)        ; partition size's?
  699.     beq.s    fdnxt0        ; if =0, not valid
  700.  
  701.     move.b    4(a0),d0    ; d0 = system indicator
  702.     beq.s    fdnxt0        ; if =0, not valid
  703.  
  704.     move.l    8(a0),d1    ; d1.l = logical start sector of drv or vol
  705.     beq.s    fdnxt0        ; if =0, not valid
  706.     ror.w    #8,d1        ; swap hi and lo byte of high word
  707.     swap    d1        ; swap hi and lo word
  708.     ror.w    #8,d1        ; swap hi and lo byte of low word
  709.  
  710.     cmpi.b    #4,d0        ; if =4,
  711.     beq.s    fdnxt2        ; valid logical drive found
  712.  
  713.     cmpi.b    #1,d0        ; if =1,
  714.     beq.s    fdnxt2        ; valid logical drive found
  715.  
  716.     cmpi.b    #5,d0        ; if =5, valid ptr to next ext volume
  717.     bne.s    fdnxt0        ; else, not valid
  718.     move.l    d1, extvol    ; offset of ext vol from start of ext DOS
  719.     bra.s    fdnxt3
  720.  
  721. fdnxt1:    moveq    #0,d0        ; return no drive found
  722.     bra.s    fdnxtr
  723.  
  724. fdnxt2:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  725. fdnxt3:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  726. fdnxtr:    rts
  727.  
  728.  
  729. ;
  730. ;+
  731. ; gembpb - find the GEMDOS partition that corresponds to the requested
  732. ;       logical drive.
  733. ; Passed:
  734. ;    a0 = buffer address for root sector
  735. ;    d1 = number of entries in partition map
  736. ;
  737. ; Assumed:
  738. ;    pbpbs = partition being looked for
  739. ;
  740. ; Returns:
  741. ;    d0.b = 0        if partition not found
  742. ;         = negative #    some kind of error
  743. ;         = positive #    system indicator of the partition
  744. ;    d1.l = starting sector of the partition (if it is found)
  745. ;-
  746. gembpb:    adda.w    #HDSIZ,a0        ; a0 -> hard disk size
  747.     tst.l    (a0)+            ; size? (a0 -> start of pmap)
  748.     beq.s    gbpb4            ; if =0, no drive will exist
  749. gbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  750.     sf    ext            ; not dealing with ext partition
  751.     bsr    fgpart            ; find partitions
  752.     tst.b    d0            ; found any?
  753.     beq.s    gbpba            ; not a valid partition
  754.     cmpi.b    #'X',d0            ; extended partition?
  755.     bne.s    gbpb1            ; if not, it's a regular partition
  756.     st    ext            ; else, it's an extended partition
  757.     move.l    #0,extvol        ; offset from start of partition = 0
  758.     move.l    d1,extrt        ; starting sector # of ext partition
  759. gbpbx:    bsr    fgnxt            ; find next logical drive
  760.     tst.b    d0            ; found any?
  761.     beq.s    gbpba            ; no logical drive found
  762.     bmi.s    gbpb2            ; error returned
  763.     cmpi.b    #'X',d0            ; extended volume?
  764.     beq.s    gbpbx            ; if so, go find next logical drive
  765. gbpb1:    subq.w    #1,pbpb            ; partition that we want?
  766.     bpl.s    gbpb3            ; if not, continue the search
  767. gbpb2:    addq.l    #8,sp            ; else BINGO!  Clean up stack
  768.     bra.s    gbpbr            ; and return
  769. gbpb3:    tst.b    ext            ; clun is in ext partition?
  770.     bne.s    gbpbx            ; if so, go find next ext vol
  771. gbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  772.     adda    #12,a0            ; index to next entry in pmap
  773.     dbra    d1,gbpb0
  774. gbpb4:    moveq    #0,d0            ; partition not found!
  775. gbpbr:    rts
  776.  
  777.  
  778. ;+
  779. ; fgpart - find a GEMDOS partition.
  780. ;
  781. ; Passed:
  782. ;    a0 = address to partition entry
  783. ;
  784. ; Returns:
  785. ;    d0.b = 0        partition is not valid
  786. ;         = positive    #    partition is a valid partition
  787. ;           (this is the first byte in p_id of the partition)
  788. ;    d1.l = starting sector # of a valid partition (if d0.b = 'G' or 'B')
  789. ;         = starting sector # of extended partition (if d0.b = 'X')
  790. ;-
  791.     .globl    fgpart
  792. fgpart:    tst.b    (a0)            ; check the valid partition flag
  793.     beq.s    fgp2            ; if =0, not valid
  794.  
  795.     tst.l    8(a0)            ; partition's size?
  796.     beq.s    fgp2            ; if =0, not valid
  797.  
  798.     cmpi.b    #'G',1(a0)        ; must find GEM as type
  799.     bne.s    fgp0            ; for REGULAR partition
  800.     cmpi.b    #'E',2(a0)        ; (ie., partition < 16Mb)
  801.     bne.s    fgp0
  802.     cmpi.b    #'M',3(a0)
  803.     beq.s    fgp3
  804.  
  805. fgp0:    cmpi.b    #'B',1(a0)        ; must find BGM as type
  806.     bne.s    fgp1            ; for BIG partition
  807.     cmpi.b    #'G',2(a0)        ; (ie., partition >= 16Mb)
  808.     bne.s    fgp1
  809.     cmpi.b    #'M',3(a0)
  810.     beq.s    fgp3
  811.  
  812. fgp1:    cmpi.b    #'X',1(a0)        ; or find XGM as type
  813.     bne.s    fgp2            ; for EXTENDED GEMDOS 
  814.     cmpi.b    #'G',2(a0)        ; partition
  815.     bne.s    fgp2            ; (ie., partition with
  816.     cmpi.b    #'M',3(a0)        ;  a linked list of
  817.     beq.s    fgp3            ;  logical drives)
  818.  
  819. fgp2:    moveq    #0,d0            ; else, not valid
  820.     bra.s    fgpr
  821.  
  822. fgp3:    move.l    4(a0),d1        ; d1.l = starting sector #
  823.     move.b    1(a0),d0        ; d0.b = first byte of p_id
  824. fgpr:    rts
  825.  
  826.  
  827. ;+
  828. ; fgnxt - find a logical drive in the extended GEMDOS partition
  829. ;
  830. ; Passed:
  831. ;    d0.b = (= 'X' if a new extended volume was found)
  832. ;           (= 0 if nxtdrv was successful for last logical drive found)
  833. ;    d1.l = starting sector # of this extended volume
  834. ;    d2.b = count down for logical drive entries (if d0.b != 'X')
  835. ;    a0.l = address of partition entry to be checked (if d0.b != 'X')
  836. ;
  837. ; Assumes:
  838. ;    cpun = current physical unit #
  839. ;    extrt = starting sector # of extended GEMDOS partition
  840. ;    extvol = offset from start of extended GEMDOS partition (in sectors)
  841. ;
  842. ; Returns:
  843. ;    d0.b = 0        no logical drive found
  844. ;         = positive #    valid logical drive found
  845. ;           (this is the first byte of p_id of the logical drive)
  846. ;         = negative #    error occured
  847. ;    d1.l = starting sector # of the logical drive (if d0.b = 'G' or 'B')
  848. ;         = starting sector # of next extended volume (if d0.b = 'X')
  849. ;-
  850.     .globl    fgnxt
  851. fgnxt:    cmpi.b    #'X',d0        ; new extended volume found?
  852.     bne.s    fgnxt0        ; if not, search for one
  853.     move.l    d1,-(sp)    ; from beginning of extended volume
  854.     move.w    cpun,-(sp)    ; physical unit number
  855.     addq.w    #2,(sp)        ; unit # including A: and B:
  856.     move.w    #-1,-(sp)    ; using a long sector number
  857.     move.w    #1,-(sp)    ; read in 1 sector
  858.     move.l    _dskbufp,-(sp)    ; buffer to read into
  859.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  860.     bsr    _ahdi_rw    ; ahdi_rw($a, buf, 1, -1, cpun, lsectno)
  861.     adda    #16,sp        ; cleanup stack
  862.     tst.w    d0        ; read successful?
  863.     bne    fgnxtr        ; if not, return error
  864.  
  865.     movea.l    _dskbufp,a0    ; a0 -> partition map
  866.     adda.w    #HDSIZ+4-12,a0    ; a0 -> 1st entry in log drive map
  867.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  868.  
  869. fgnxt0:    subq.w    #1,d2        ; more entries to search?
  870.     bmi.s    fgnxt3        ; if not, return
  871.  
  872.     adda    #12,a0        ; a0 -> entry to be examined
  873.     tst.l    8(a0)        ; partition size's?
  874.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  875.  
  876.     tst.b    (a0)        ; check the valid partition flag
  877.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  878.  
  879.     move.l    4(a0),d1    ; d1.l = logical start sector of drv or vol
  880.  
  881.     cmpi.b    #'G',1(a0)    ; must find GEM as type
  882.     bne.s    fgnxt1        ; for REGULAR partition
  883.     cmpi.b    #'E',2(a0)    ; (ie., partition < 16Mb)
  884.     bne.s    fgnxt1
  885.     cmpi.b    #'M',3(a0)
  886.     beq.s    fgnxt4
  887.  
  888. fgnxt1:    cmpi.b    #'B',1(a0)    ; must find BGM as type
  889.     bne.s    fgnxt2        ; for BIG partition
  890.     cmpi.b    #'G',2(a0)    ; (ie., partition >= 16Mb)
  891.     bne.s    fgnxt2
  892.     cmpi.b    #'M',3(a0)
  893.     beq.s    fgnxt4
  894.  
  895. fgnxt2:    cmpi.b    #'X',1(a0)    ; or find XGM as type
  896.     bne.s    fgnxt3        ; for EXTENDED GEMDOS 
  897.     cmpi.b    #'G',2(a0)    ; partition
  898.     bne.s    fgnxt3        ; (ie., partition with
  899.     cmpi.b    #'M',3(a0)    ;  a linked list of
  900.     bne.s    fgnxt0        ;  logical drives)
  901.  
  902.     move.l    d1, extvol    ; offset of ext vol from start of ext GEMDOS
  903.     bra.s    fgnxt5
  904.  
  905. fgnxt3:    moveq    #0,d0        ; return no drive found
  906.     bra.s    fgnxtr
  907.  
  908. fgnxt4:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  909. fgnxt5:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  910.     move.b    1(a0),d0    ; d0.b = first byte of p_id
  911. fgnxtr:    rts
  912.  
  913.  
  914. ;
  915. ;+
  916. ; getbpb(dev, sectorno)
  917. ; WORD dev;        4(sp).w
  918. ; LONG sectorno;    6(sp).l
  919. ;
  920. ; Assume -
  921. ;    cpun contains physical unit number of dev
  922. ;-
  923. getbpb:    move.l    $6(sp),-(sp)    ; sector # of boot sector
  924.     move.w    cpun,-(sp)    ; physical unit
  925.     addq.w    #2,(sp)        ; unit # including A: and B:
  926.     move.w    #-1,-(sp)    ; using a long sector number
  927.     move.w    #1,-(sp)    ; 1 sector
  928.     move.l    _dskbufp,-(sp)    ; buffer
  929.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  930.     bsr    _ahdi_rw    ; ahdi_rw(8, buf, 1, -1, cpun, lsectno)
  931.     adda    #16,sp        ; clean up stack
  932.     tst.w    d0        ; successful?
  933.     beq.s    getb0        ; if so, go on normally
  934.                 ; else let user retry
  935. getb9:    move.w    4(sp),d1    ; d1 = drive # excluding A: and B:
  936.     bsr    critic
  937.     cmpi.l    #CRITRETRY,d0    ; retry?
  938.     bne    getb7        ; if not, return
  939.     bra.s    getbpb        ; else read again
  940.  
  941. getb0:    movea.l    _dskbufp,a0    ; a0 -> boot sector image
  942.     movea.l    #bpbs,a2    ; a2 -> bpb
  943.  
  944.     move.w    #$0b,d0
  945.     bsr    getlhw
  946.     cmp.w    maxssz,d0    ; is sector size too big?
  947.     bhi    getb7        ; if it is, can't handle it
  948.     move.w    d0,(a2)+    ; =byt/sec
  949.     beq    getb7        ; if =0, bad data
  950.     move.w    d0,d1
  951.     divu    #512,d0        ; d0.b = ratio log : phys sector size
  952.     move.w    d0,sizr        ; save the ratio
  953.  
  954.     clr.w    d0
  955.     move.b    $d(a0),d0
  956.     move.w    d0,(a2)+    ; = #sectors/cluster
  957.     beq    getb7        ; if =0, bad data
  958.  
  959.     mulu    d1,d0
  960.     move    d0,(a2)+    ; = #bytes/cluster
  961.  
  962.     move    #$11,d0
  963.     bsr    getlhw        ; number of directory entries
  964.     tst    d0        ; num o' entries ?= 0
  965.     beq    getb7        ; if so, bad data
  966.      mulu    #32,d0        ; size of each entry
  967.     divu    d1,d0        ; number of sectors required
  968.     move.l    d0,d1
  969.     swap    d1
  970.     tst    d1
  971.     beq.s    getb1
  972.     addq    #1,d0        ; round up
  973. getb1:    move    d0,(a2)+    ; =rdlen
  974.     move    d0,d2
  975.  
  976.     move    #$16,d0
  977.     bsr    getlhw
  978.     move    d0,(a2)+    ; =FATsize
  979.     beq    getb7        ; if =0, bad data
  980.     move    d0,d1
  981.     move    d0,fsiz        ; save FAT size
  982.  
  983.     move    #$e,d0
  984.     bsr    getlhw        ; number of reserved sectors
  985.     add    d1,d0
  986.     move    d0,(a2)+    ; =2nd FAT start
  987.     move    d0,fatrec    ; save 2nd FAT start 
  988.  
  989.     add    d1,d0        ; plus size of second fat
  990.     add    d2,d0        ; plus rdlen
  991.     move    d0,(a2)+    ; = data start
  992.     move    d0,d2        ; save start of data
  993.  
  994.     move    #$13,d0
  995.     bsr    getlhw        ; number of sectors on media
  996.     sub    d2,d0        ; subtract # used by FATs,dir,boot
  997.     beq    getb7        ; if =0, bad data
  998.     clr.l    d1
  999.     move    d0,d1
  1000.     clr    d0
  1001.     move.b    $d(a0),d0    ; number of sectors/cluster
  1002.     divu    d0,d1        ; rounding down
  1003.     move    d1,(a2)+    ; =number of clusters
  1004.     move    bfat,(a2)    ; =flags, 12 or 16 bit fats
  1005.  
  1006.     move.w    sizr,d2        ; d2 = current sector size ratio
  1007.     lea    sratio,a1    ; a1 -> sector size ratio table
  1008.     move.w    4(sp),d0    ; d0 = drive number
  1009.     move.b    d2,(a1,d0.w)    ; update sector size ratio in table
  1010.  
  1011.     btst.b    #6,cpun+1    ; is unit removable?
  1012.     beq    getb6        ; if not, can skip the fat checksum
  1013.  
  1014.     lea    serno,a1    ; a1 -> table of serial #s
  1015.     mulu.w    #SERLEN,d0    ; dev# * SERLEN to index into table
  1016.     adda.l    d0,a1        ; a1 -> serial # of dev
  1017.     move.w    #SERLEN-1,d1    ; length of serial # - 1
  1018. getb2:    move.b    $8(a0,d1.w),(a1,d1.w)    ; update serial # of dev
  1019.     dbra    d1,getb2
  1020.  
  1021.     lea    fatsum,a2    ; a2 -> FAT check sum table
  1022.     move.w    4(sp),d0    ; d0 = dev number
  1023.     mulu    #FATLEN,d0    ; d0*FATLEN = to index into table
  1024.     adda.l    d0,a2        ; a2 -> FAT check sum tbl of dev
  1025.  
  1026.     move.w    fatrec,d0    ; d0 = log starting sector of 2nd FAT
  1027.     mulu    d2,d0        ; (in 512-byte sectors)
  1028.     movea.l    $6(sp),a1    ; a1 = starting sector of drive
  1029.     adda.l    d0,a1        ; a1 = phys starting sector of 2nd FAT
  1030.  
  1031.     move.w    fsiz,d1        ; d1 = # FAT sectors to read
  1032.     subq.l    #1,d1        ;    = FAT size - 1
  1033.  
  1034. getb3:    move.w    sizr,d2        ; d2 = count per FAT sector
  1035.     subq.w    #1,d2
  1036.      clr.l    temp        ; initialize the sum
  1037. getb4:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1038.     move.l    a1,-(sp)    ; from sector a1
  1039.     move.w    cpun,-(sp)    ; physical unit
  1040.     addq.w    #2,(sp)        ; unit # including A: and B:
  1041.     move.w    #-1,-(sp)    ; using a long sector number
  1042.     move.w    #1,-(sp)    ; read 1 phys sector
  1043.     move.l    a0,-(sp)    ; buffer (in _dskbufp)
  1044.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  1045.     bsr    _ahdi_rw    ; ahdi_rw($a, buf, 1, -1, cpun, lsecno)
  1046.     adda    #16,sp        ; clean up stack
  1047.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1048.     tst.w    d0        ; read successful?
  1049.     beq    getb5        ; if so, go on normally
  1050.                 ; else let user retry
  1051. getba:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1052.     move.w    24(sp),d1    ; d1 = drive # excluding A: and B:
  1053.     bsr    critic        ; critical error handler
  1054.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1055.     cmpi.l    #CRITRETRY,d0    ; retry?
  1056.     beq.s    getb4        ; if so, try again
  1057.     bra    getb7        ; else return
  1058.  
  1059. getb5:    bsr    bsum        ; add up values in the sector
  1060.     addq    #1,a1        ; get ready for next sector
  1061.     dbra    d2,getb4    ; until one logical FAT sector is done
  1062.  
  1063.     bsr    csum        ; find the checksum
  1064.     move.b    d0,(a2)+    ; update checksum for this FAT sector
  1065.     dbra    d1,getb3    ; until all sectors are checked
  1066.  
  1067. getb6:    move.w    $4(sp),d0    ; d0 = dev number
  1068.     lea    mcflgs,a0    ; load address of mcflgs table
  1069.     clr.b    (a0,d0.w)    ; clear mcflg for dev
  1070.  
  1071.     lea    xst,a0        ; a0 -> drive existence table
  1072.     move.b    #2,(a0,d0.w)    ; dev definitely exists
  1073.  
  1074.     lea    fatst,a0    ; a0 -> FAT start sector table
  1075.     asl.w    #1,d0        ; offset = dev# * 2 (tbl of words)
  1076.     move    fatrec,(a0,d0.w); update FAT starting sect#
  1077.  
  1078.     lea    fatend,a0    ; a0 -> FAT end sector table
  1079.     move.w    fatrec,d1    ; d1 = fatend(dev)
  1080.     add.w    fsiz,d1        ;    = fatrec + fsiz - 1
  1081.     subq.w    #1,d1    
  1082.     move.w    d1,(a0,d0.w)    ; fatend(dev) = fatrec + fsiz - 1
  1083.  
  1084.     lea    start,a0    ; a0 -> beginning of start table
  1085.     asl.w    #1,d0        ; offset = dev# * 2 * 2 (tbl of longs)
  1086.     move.l    $6(sp),(a0,d0.w); update starting sect# of dev
  1087.  
  1088.     move.l    #bpbs,d0    ; no errors, return ptr to BPB
  1089.     bra.s    getb8        ; return
  1090.  
  1091. getb7:    moveq    #-1,d0        ; error
  1092. getb8:    rts
  1093.  
  1094.  
  1095. ;+
  1096. ; WORD getlhw(d0=offset)
  1097. ; returns word (low,high) from 0(D0,A0)
  1098. ;-
  1099.     .globl    getlhw
  1100. getlhw:    move    d1,-(sp)    ; preserve d1
  1101.     move.b    1(a0,d0.w),d1
  1102.     lsl.w    #8,d1
  1103.     move.b    0(a0,d0.w),d1
  1104.     move    d1,d0
  1105.     move    (sp)+,d1
  1106.     rts
  1107.  
  1108.  
  1109. ;+
  1110. ; bsum
  1111. ;
  1112. ; Passed:
  1113. ;    a0 = starting address of buffer to be summed
  1114. ;    temp.l = current sum
  1115. ;
  1116. ; Function:
  1117. ;      - sum up 512 bytes of a buffer 4 bytes at a time
  1118. ;    - save the sum in temp.l
  1119. ;
  1120. ; Algorithm for check summing the FAT:
  1121. ;    - add up bytes in the buffer 4 bytes at a time    (in bsum)
  1122. ;    - if the sum is non-zero, XOR the high word     (in csum)
  1123. ;      with the low word of the 4-byte result
  1124. ;    - now take this 2-byte result, and XOR its high    (in csum)
  1125. ;      byte with its low byte to get the final 1-byte
  1126. ;      result
  1127. ;-
  1128. bsum:    movem.l    d1/a0,-(sp)        ; save d1, a0
  1129.     move.l    temp,d0            ; d0 = current sum
  1130.     move    #127,d1            ; count
  1131. bsum0:    add.l    (a0)+,d0        ; add 4 bytes to sum
  1132.     dbra    d1,bsum0        ; until all bytes are added
  1133.     move.l    d0,temp            ; temp.l = new sum
  1134.     movem.l    (sp)+,d1/a0        ; restore d1, a0
  1135.     rts
  1136.  
  1137.  
  1138. ;+
  1139. ; csum
  1140. ; (a) XOR the high word with the low word of temp.l
  1141. ; (b) then XOR the high byte with the low byte of result of (a)
  1142. ;
  1143. ; Returns:
  1144. ;    d0.b = checksum
  1145. ;-
  1146. csum:    move.w    temp+2,d0        ; d0.w = low word of result
  1147.     eor.w    d0,temp            ; exclusive-or low and high word
  1148.     move.b    temp+1,d0        ; d0.b = low byte of xor-ed result
  1149.     eor.b    d0,temp            ; exclusive-or low and high byte
  1150.     move.b    temp,d0
  1151.     rts                ; d0.b = checksum
  1152.  
  1153.  
  1154. ;
  1155. ;+
  1156. ;  Read/Write sectors
  1157. ;
  1158. ;    Synopsis:    _ahdi_rw(rw, buf, count, recno, dev, lrecno)
  1159. ;        WORD rw        4(sp).w        ; non-zero -> write
  1160. ;        char *buf    6(sp).l
  1161. ;        WORD count    $a(sp).w
  1162. ;        WORD recno    $c(sp).w
  1163. ;        WORD dev    $e(sp).w
  1164. ;        LONG lrecno    $10(sp).l    ; optional
  1165. ;-
  1166.  
  1167. ; stack frame offsets
  1168. xrw    equ    8
  1169. xbuf    equ    10
  1170. xcount    equ    14
  1171. xrecno    equ    16
  1172. xdev    equ    18
  1173. xlrecno    equ    20
  1174.  
  1175.     .globl    _sasi_rw
  1176.     .globl    _ahdi_rw
  1177. _sasi_rw:
  1178. _ahdi_rw:
  1179.     link    a6,#0            ; create a frame pointer
  1180.     subq.w    #2,xdev(a6)        ; drive # excluding A: and B:
  1181.  
  1182.     move.w    xdev(a6),d0        ; d0 = device number
  1183.     btst.b    #3,xrw+1(a6)        ; is this a physical operation?
  1184.     beq.s    getcpun            ; if not, find physical unit number
  1185.     move.w    d0,cpun            ; else, dev# passed is phys unit #
  1186.     move.w    #1,sizr            ; sector size ratio = 1
  1187.     bra    ahrw1            ; go start the r/w
  1188. getcpun:                ; map log -> phys unit number
  1189.     lea    pun,a0            ; a0 -> pun table
  1190.     move.b    (a0,d0.w),cpun+1    ; cpun = pun of dev
  1191.     
  1192.     lea    sratio,a0        ; a0 -> sector size ratio table
  1193.     move.b    (a0,d0.w),sizr+1    ; sizr = current sector size ratio
  1194.                     ;     (coerced to word)
  1195.     lea    start,a0        ; a0 -> start table
  1196.     move.w    d0,d1            ; d1 = drive #
  1197.     add.w    d1,d1            ; d1*2*2 (index into tbl of longs)
  1198.     add.w    d1,d1
  1199.     move.l    (a0,d1.w),cstart    ; cstart = dev starting sector
  1200.  
  1201.     btst.b    #1,xrw+1(a6)        ; ignore media change?
  1202.     bne    ahrw1            ; if yes, go ahead and do r/w
  1203.                     ; else check for media change
  1204.     lea    mcflgs,a0        ; a0 -> mcflgs of drive
  1205.     move.b    (a0,d0.w),d0        ; d0 = mcflg of dev
  1206.     beq    ahrw1            ; if media not changed, go do r/w
  1207.  
  1208.     cmpi.b    #2,d0            ; is media definitely changed?
  1209.     beq    retmc            ; if yes, return media has changed
  1210.                     ; else, check if media has changed
  1211.                     ; try to read dev's boot sector
  1212. chkmc:    move.l    cstart,-(sp)        ; dev starting sector
  1213.     move.w    cpun,-(sp)        ; physical unit number
  1214.     addq.w    #2,(sp)            ; unit # including A: and B:
  1215.     move.w    #-1,-(sp)        ; using a long sector number
  1216.     move.w    #1,-(sp)        ; 1 sector
  1217.     move.l    _dskbufp,-(sp)        ; buffer
  1218.     move.w    #$a,-(sp)        ; phys mode and no media change error
  1219.     bsr    _ahdi_rw        ; ahdi_rw($a, buf, 1, -1, cpun, sectno)
  1220.     adda    #16,sp            ; clean up stack
  1221.     tst.w    d0            ; read successful?
  1222.     beq.s    chkser            ; yes, go check serial number
  1223.  
  1224.     move.w    xdev(a6),d1        ; device number
  1225.     bsr    critic            ; call critical error handler
  1226.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1227.     beq.s    chkmc            ; if yes, go back and try it
  1228.     bra    ahrw7            ; else return
  1229.  
  1230. chkser:    lea    serno,a1        ; a1 -> serial #s table
  1231.     move.w    xdev(a6),d0        ; d0 = dev number
  1232.     mulu.w    #SERLEN,d0        ; *SERLEN for index into table
  1233.     adda.l    d0,a1            ; a1 -> serial # of dev
  1234.  
  1235.     move.l    _dskbufp,a2        ; a2 -> boot sector
  1236.     addq.w    #8,a2            ; a2 -> serial # in boot sector
  1237.      move.w    #SERLEN-1,d0        ; d0 = count for comparison
  1238. cmpser:    cmpm.b    (a2)+,(a1)+        ; serial # read ?= serial # recorded
  1239.     bne    ismc            ; if not, media has changed
  1240.     dbra    d0,cmpser        ; compare next byte of serial #
  1241.                     ; serial # hasn't changed, try FAT
  1242.     move.w    xdev(a6),d0        ; d0 = dev number
  1243.     lea    fatsum,a1        ; a1 -> fat checksum table
  1244.     move.w    #FATLEN,d1        ; d1.w = index into table
  1245.     mulu    d0,d1
  1246.     adda.l    d1,a1            ; a1 -> fat checksum of dev
  1247.  
  1248.     add.w    d0,d0            ; d0*2 = index into table of words
  1249.     lea    fatst,a2        ; a2 -> FAT start table
  1250.     move.w    (a2,d0.w),fatrec    ; fatrec = fatst(dev)
  1251.  
  1252.     lea    fatend,a2        ; a2 -> FAT end table
  1253.     move.w    (a2,d0.w),d1        ; d1 = counter to scan FAT table
  1254.     sub.w    fatrec,d1        ;    = fatend(dev) - fatst(dev)
  1255.  
  1256.     movea.l    cstart,a2        ; a2 = start sector of dev
  1257.     move.w    fatrec,d2        ; d2 = fatst(dev)
  1258.     mulu    sizr,d2            ; d2 = fatst(dev) in 512-byte sector
  1259.     adda.l    d2,a2            ; a2 = phys start sector of 2nd FAT
  1260.  
  1261.     movea.l    _dskbufp,a0        ; a0 -> dskbuf
  1262. cmpfat:    move.w    sizr,d2            ; d2 = # reads per FAT sector
  1263.     subq.w    #1,d2            ; d2 - 1 = counter
  1264.     clr.l    temp            ; initialize sum
  1265. cfat0:    movem.l    d1-d2/a0-a2,-(sp)    ; save d1, d2, a0, a1, a2
  1266.                     ; try to read this FAT sector
  1267.     move.l    a2,-(sp)        ; at sector a2
  1268.     move.w    cpun,-(sp)        ; physical unit number
  1269.     addq.w    #2,(sp)            ; unit # including A: and B:
  1270.     move.w    #-1,-(sp)        ; using a long sector number
  1271.     move.w    #1,-(sp)        ; 1 sector
  1272.     move.l    a0,-(sp)        ; buffer
  1273.     move.w    #$a,-(sp)        ; phys mode and no media change error
  1274.     bsr    _ahdi_rw        ; ahdi_rw($a, buf, 1, -1, cpun, sectno)
  1275.     adda    #16,sp            ; clean up stack
  1276.     movem.l    (sp)+,d1-d2/a0-a2    ; restore d1, d2, a0, a1, a2
  1277.     tst.w    d0            ; read successful?
  1278.     beq.s    chkfat            ; if yes, go check sum FAT sectors
  1279.                     ; else assume it's read error
  1280.     movem.l    d1-d2/a0-a2,-(sp)    ; save registers d1, d2, a0, a2
  1281.     move.w    xdev(a6),d1        ; drive number
  1282.     bsr    critic
  1283.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers d1, d2, a0, a2
  1284.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1285.     beq.s    cfat0            ; if yes, go back and try it
  1286.     bra    ahrw7            ; else return
  1287.  
  1288. chkfat:    bsr    bsum            ; if ok, sum the sector
  1289.     addq    #1,a2            ; ready for try next sector
  1290.     dbra    d2,cfat0        ; until one FAT sector is summed
  1291.  
  1292.     bsr    csum            ; find the checksum
  1293.     cmp.b    (a1)+,d0        ; checksum recorded ?= checksum found
  1294.     bne    ismc            ; if not, media has changed
  1295.     dbra    d1,cmpfat        ; until all sectors are checked
  1296.  
  1297.     lea    mcflgs,a0        ; a0 -> mcflgs table
  1298.     adda.w    xdev(a6),a0        ; a0 -> mcflg of drive
  1299.     clr.b    (a0)            ; clear mcflg for dev
  1300.  
  1301. ahrw1:    tst.w    xcount(a6)        ; any sector to r/w?
  1302.     beq    ahrw6            ; if =0, done
  1303.  
  1304.     cmpi.w    #-1,xrecno(a6)        ; does recno = -1?
  1305.     bne.s    ahrw2            ; if not, we have a word record #
  1306.     movea.l    xlrecno(a6),a1        ; a1.l = start record #
  1307.     bra.s    ahrw3
  1308. ahrw2:    moveq    #0,d0            ; coerce to long
  1309.     move.w    xrecno(a6),d0        ; d0.l = recno
  1310.     movea.l    d0,a1            ; a1.l = start record #
  1311.  
  1312. ahrw3:    move.l    a1,strec        ; save first sector to r/w
  1313.     move.l    a1,d1            ; d1.l = starting sector to r/w
  1314.     moveq    #0,d2            ; coerce to long
  1315.     move.w    xcount(a6),d2        ; d2.l = #sectors to r/w
  1316.     adda.l    d2,a1            ; a1.l = last sector to r/w
  1317.     subq.l    #1,a1            ;      = first sector + count - 1
  1318.     move.l    a1,endrec        ; save last sector to r/w
  1319.     move.l    xbuf(a6),stbuf        ; save starting buffer address
  1320.  
  1321.     btst.b    #3,xrw+1(a6)        ; physical operation?
  1322.     bne.s    ahrw4            ; if so, ready to r/w
  1323.                     ; else log -> phys sector mapping
  1324.     mulu    sizr,d1            ; d1.l    = phys start sector to r/w
  1325.     add.l    cstart,d1        ;    = dev start sect + sect #
  1326.     mulu    sizr,d2            ; d2.l = # phys 512-byte sects to r/w
  1327.  
  1328. ahrw4:    move.w    xdev(a6),-(sp)        ; device # (excluding A: and B:)
  1329.     move.l    d1,-(sp)        ; starting sector
  1330.     move.l    d2,-(sp)        ; count (in sectors)
  1331.     move.l    xbuf(a6),-(sp)        ; buffer
  1332.     move.w    xrw(a6),-(sp)        ; read write flag
  1333.     bsr    _do_rw            ; do the read or write
  1334.     adda    #16,sp            ; clean up stack
  1335.     tst.l    d0            ; successful?
  1336.     beq.s    chkwr            ; if so, go on to wrap up
  1337.  
  1338.     cmpi.l    #E_CHNG,d0        ; media change detected?
  1339.     bne    ahrw7            ; if not, give up
  1340.     btst.b    #3,xrw+1(a6)        ; is this a physical operation?
  1341.     bne    ahrw7            ; if so, return media change error
  1342.     bra    chkmc            ; and go check if media has changed 
  1343.                     ; check if wrote to boot sector
  1344. chkwr:    move.w    xrw(a6),d0        ; d0 = r/w and flags word
  1345.     btst    #0,d0            ; read or write?
  1346.     beq    ahrw6            ; if read, done
  1347.     btst.b    #6,cpun+1        ; is drive removable?
  1348.     beq    ahrw6            ; if not, done
  1349.     btst    #3,d0            ; was it a physical operation?
  1350.     bne    ahrw6            ; if it was, done
  1351.     tst.l    strec            ; wrote to boot sector?
  1352.     bne.s    wrfat            ; if not, check if wrote to FATs
  1353.     lea    mcflgs,a0        ; else, a0 -> mcflgs table
  1354.     adda.w    xdev(a6),a0        ; a0 -> dev's mcflg
  1355.     move.b    #2,(a0)            ; assume medium has changed
  1356.                     ; check if wrote to FATs
  1357. wrfat:    lea    fatend,a0        ; a0 -> fatend table
  1358.     move.w    xdev(a6),d0        ; d0 = device number
  1359.     add.w    d0,d0            ; d0*2 = index into table of words
  1360.     moveq    #0,d1            ; coerce to long
  1361.     move.w    (a0,d0.w),d1        ; d1 = last sector of last FAT
  1362.     cmp.l    strec,d1        ; wrote beyond the last FAT?
  1363.     blt    ahrw6            ; if so, done
  1364.  
  1365.     lea    fatst,a0        ; a0 -> fatst table
  1366.     moveq    #0,d2            ; coerce to long
  1367.     move.w    (a0,d0.w),d2        ; d2 = first sector of last FAT
  1368.     cmp.l    endrec,d2        ; wrote before the last FAT?
  1369.     bgt    ahrw6            ; if so, done
  1370.                     ; else update FAT sector checksums
  1371.     move.l    stbuf,a0        ; a0 -> buffer w/ written data
  1372.     lea    fatsum,a1        ; a1 -> start of fatsum table
  1373.     move.w    xdev(a6),d0        ; d0 = dev number
  1374.     mulu.w    #FATLEN,d0        ; d0 = offset to dev's FAT chksum
  1375.     adda.l    d0,a1            ; a1 -> dev's first FAT chksum
  1376.     move.l    strec,d0        ; d0 = first sector wrote to
  1377.     sub.l    d2,d0            ; d0 = strec - start(last FAT)
  1378.     beq.s    wrfat2            ; if strec = start(last FAT), 
  1379.                     ;     no adjustments needed
  1380.      blt.s    wrfat1            ; if strec < start(last FAT)
  1381.                     ;     begin from start(last FAT)
  1382.     move.l    strec,d2        ; else begin from strec
  1383.     adda.l    d0,a1            ; a1 -> fatsum to be updated
  1384.     bra.s    wrfat2
  1385.  
  1386. wrfat1:    neg.l    d0            ; d0 = index into stbuf
  1387.     asl.l    #8,d0            ;    = (start(last FAT) - strec)*512
  1388.     add.l    d0,d0
  1389.     adda.l    d0,a0            ; a0 -> addr of buf for update
  1390.  
  1391. wrfat2:    cmp.l    endrec,d1        ; if end(last FAT) <= endrec
  1392.     ble.s    wrfat3            ;     stop at end(last FAT)
  1393.     move.l    endrec,d1        ; else stop at endrec
  1394.  
  1395. wrfat3:    sub    d2,d1            ; d1 = # sectors to be processed
  1396. wrfat4:    move.w    sizr,d2            ; d2 = # phys sect per log sect
  1397.     subq.w    #1,d2            ; dbra likes one less
  1398.     clr.l    temp            ; initialize sum
  1399. wrfat5:    bsr    bsum            ; sum up one 512-byte sector
  1400.     adda.l    #512,a0            ; point to next 512 bytes
  1401.     dbra    d2,wrfat5        ; until one logical sector is done
  1402.     bsr    csum            ; obtain checksum
  1403.     move.b    d0,(a1)+        ; record new fat checksum
  1404.     dbra    d1,wrfat4        ; do until all are updated
  1405.  
  1406. ahrw6:    clr.l    d0            ; got here with no errors!
  1407.     bra.s    ahrw7
  1408.  
  1409. ismc:    lea    mcflgs,a0        ; a0 -> mcflgs table
  1410.     adda.w    xdev(a6),a0        ; a0 -> dev's mcflg
  1411.     move.b    #2,(a0)            ; set mcflg for dev to has changed
  1412.     lea    xst,a0            ; a0 -> drive existence table
  1413.     adda.w    xdev(a6),a0        ; a0 -> xst flag of dev
  1414.     move.b    #2,(a0)            ; assume dev exists
  1415. retmc:    move.l    #E_CHNG,d0        ; yes, return media change error
  1416.  
  1417. ahrw7:    btst.b    #0,xrw+1(a6)        ; read or write?
  1418.     bne.s    ahrwd            ; if write, done
  1419.     tst.b    _cachexst        ; does a cache exist?
  1420.     beq.s    ahrwd            ; if not, done
  1421.                     ; else dump the cache
  1422.     move.l    d0,-(sp)        ; save the status
  1423.     move    sr,-(sp)        ; go to IPL 7
  1424.     ori    #$700,sr        ; no interrupts right now kudasai
  1425.     movecacrd0            ; d0 = (cache control register)
  1426.     ori.w    #$808,d0        ; dump both the D and I cache
  1427.     moved0cacr            ; update cache control register
  1428.     move    (sp)+,sr        ; restore interrupt state
  1429.     move.l    (sp)+,d0        ; restore the return value
  1430.  
  1431. ahrwd:    unlk    a6
  1432.     rts
  1433.  
  1434.  
  1435. ;+
  1436. ; smove() - Copy unaligned sectors (this is *supposed* to be slow!)
  1437. ;
  1438. ; Passed:
  1439. ;    d0 = # of sectors to be moved
  1440. ;    d1 = size of operation    (0 - byte; 2 - long;)
  1441. ;    a2 -> source buffer
  1442. ;    a1 -> dest buffer
  1443. ;
  1444. ; Trashes: d0, a1, a2
  1445. ;-
  1446. smove:    move.w    d1,-(sp)        ; save size of operation
  1447.     neg.w    d1            ; d0 = count
  1448.     addi.w    #9,d1            ;    = (# sectors * 512) >> op size
  1449.     asl.w    d1,d0            ;
  1450.     subq.w    #1,d0            ; dbra likes one less
  1451.     move.w    (sp)+,d1        ; restore operation size
  1452.     bne.s    smove2            ; if non-zero, use move longs
  1453.  
  1454. smove1:    move.b    (a2)+,(a1)+
  1455.     dbra    d0,smove1
  1456.     rts
  1457.  
  1458. smove2:    move.l    (a2)+,(a1)+
  1459.     dbra    d0,smove2
  1460.     rts
  1461.  
  1462.  
  1463. ;
  1464. ;+
  1465. ; _do_rw - called to read/write no more than 128K to an even boundary
  1466. ;
  1467. ; Passed:
  1468. ;    rw    4(sp).w        ; non-zero -> write
  1469. ;    buf    6(sp).l
  1470. ;    count    $a(sp).l    ; in # phys (512-byte) sectors
  1471. ;    recno    $e(sp).l    ; physical starting sector for r/w
  1472. ;    dev    $12(sp).w    ; log dev # exluding A: and B:
  1473. ;
  1474. ; Assumes:
  1475. ;    cpun = current physical unit to r/w
  1476. ;    if in logical mode, cstart = physical starting sector # of curr dev
  1477. ;
  1478. ; Mar-05-1990 ml.
  1479. ;    All I/O to ACSI and SCSI non-accessible memory will be done by
  1480. ; using the fast ram buffer (if there is one) or the diskbuf as an inter-
  1481. ; mediate stop for the transfer.
  1482. ;
  1483. ; ACSI accessible memory:    $00000000 -> $003fffff
  1484. ;                $ff000000 -> $ff3fffff
  1485. ; SCSI non-accessible 
  1486. ; memory on the TT:        $c0000000 -> $fcffffff
  1487. ;                $fe000000 -> $feffffff
  1488. ;
  1489. ; Mar-07-1990 ml.
  1490. ;    Do not have to take care of cases when Rwabs() is supplied with
  1491. ; a buffer that would cross different kinds of memory.
  1492. ; ("It's deadly!" said AKP. :) )
  1493. ;-
  1494. yrw    equ    $8
  1495. ybuf    equ    $a
  1496. ycount    equ    $e
  1497. yrecno    equ    $12
  1498. ydev    equ    $16
  1499.  
  1500. ; Memory that ACSI _can_ DMA to
  1501. STDUAL    equ    $003fffff    ; upper limit of ST dual-purpose RAM
  1502. STCMPIL    equ    $ff000000    ; lower limit of ST compatible image
  1503. STCMPIH    equ    $ff3fffff    ; upper limit of ST compatible image
  1504.  
  1505. ; Memory that SCSI _cannot_ DMA to (non-DW)
  1506. A32D16L    equ    $c0000000    ; lower limit of A32:D16 Memory/Peripherals
  1507. A32D16H    equ    $fcffffff    ; upper limit of A32:D16 Memory/Peripherals 
  1508. VA24D16    equ    $fe000000    ; lower limit of VMEbus A24:D16
  1509. VA16D16    equ    $feffffff    ; upper limit of VMEbus    A16:D16
  1510.  
  1511. ; Cookies
  1512. _FRB    equ    $5f465242        ; _FRB
  1513.  
  1514. _do_rw:    link    a6,#0            ; create a frame pointer
  1515.     move.l    ycount(a6),d2        ; d2.l = # sectors requested to r/w
  1516.      movea.l    ybuf(a6),a1        ; a1.l = buffer addr to r/w
  1517.     btst.b    #3,cpun+1        ; talking SCSI?
  1518.     bne    scrw0            ; if yes, go for it
  1519.                     ; else talk ACSI
  1520.     cmp.l    #MAXACSECTS,d2        ; more than one ACSI DMAful?
  1521.     bls.s    acrw1            ; if not, ready to r/w
  1522.     move.l    #MAXACSECTS,d2        ; else r/w only one ACSI DMAful
  1523.  
  1524. acrw1:    btst.b    #0,ybuf+3(a6)        ; buffer on odd boundary?
  1525.     bne.s    itrw0            ; if so, do intermediate transfer
  1526.  
  1527.     cmpa.l    #STDUAL,a1        ; buf within ACSI accessible memory?
  1528.     bls    rw1            ; if so, go ahead with the I/O
  1529.     cmpa.l    #STCMPIL,a1        ; else, do intermediate transfer
  1530.     bcs.s    itrw0
  1531.     cmpa.l    #STCMPIH,a1
  1532.     bls    rw1
  1533.                     ; doing intermediate transfer
  1534. itrw0:    moveq    #0,d1            ; assume moving 1 byte at a time
  1535.     btst.b    #0,ybuf+3(a6)        ; odd boundary?
  1536.     bne.s    itrw1            ; if so, assumption ok
  1537.     moveq    #2,d1            ; else move 1 long at a time
  1538.  
  1539. itrw1:    tst.l    frbbuf            ; is there a fast RAM buffer?
  1540.     bne.s    itrw2            ; if there is one, use it
  1541.                     ; else look for _FRB
  1542.     move.l    d1,-(sp)        ; save d1
  1543.     move.l    #frbbuf,-(sp)        ; pointer to fast RAM buffer
  1544.     move.l    #_FRB,-(sp)        ; looking for cookie _FRB
  1545.     bsr    _getcookie        ; 
  1546.     addq.w    #8,sp            ; clean up stack
  1547.     move.l    (sp)+,d1        ; restore d1
  1548.     tst.w    d0            ; found _FRB?
  1549.     bne.s    itrw2            ; if so, use it
  1550.                     ; else use dskbuf
  1551.     movea.l    _dskbufp,a1        ; a1 -> dskbuf
  1552.     cmpi.w    #2,d2            ; can only do 2 at a time tops
  1553.     bls.s    itrw3
  1554.     move.w    #2,d2
  1555.     bra.s    itrw3
  1556.  
  1557. itrw2:    movea.l    frbbuf,a1        ; use the Fast RAM Buffer
  1558.     cmpi.w    #RAMRSV,d2        ; can only do RAMRSV at a time tops
  1559.     bls.s    itrw3
  1560.     move.w    #RAMRSV,d2
  1561.  
  1562. itrw3:    btst.b    #0,yrw+1(a6)        ; is this a read?
  1563.     beq.s    rw1            ; if so, go fill buffer from disk
  1564.                     ; else fill buffer here
  1565.     move.l    a1,-(sp)        ; preserve a1 = dest
  1566.     movea.l    ybuf(a6),a2        ; a2 = source
  1567.     move.w    d2,d0            ; # sectors to be moved
  1568.     bsr    smove            ; move sectors from a2 to a1
  1569.     movea.l    (sp)+,a1        ; restore a1.l = dest
  1570.     bra.s    rw1            ; go do the r/w
  1571.  
  1572. scrw0:    cmpi.l    #MAXSCSECTS,d2        ; more than one SCSI DMAful?
  1573.     bls.s    scrw1            ; if not, ready to r/w
  1574.     move.l    #MAXSCSECTS,d2        ; r/w only one SCSI DMAful?
  1575.  
  1576. scrw1:    
  1577.  
  1578. .if    SCDMA                ; if doing SCSI DMA
  1579. .if    !SCFRDMA            ; if no SCSI DMA to fast RAM
  1580.     cmpi.b    #$01,ybuf(a6)        ; is destination buffer in fast RAM?
  1581.     beq    itrw0            ; if so, do intermediate transfer
  1582. .endif    ;!SCFRDMA
  1583.  
  1584.     cmpa.l    #A32D16L,a1        ; buf in SCSI non-accessible
  1585.     bcs.s    rw1            ;  memory?
  1586.     cmpa.l    #A32D16H,a1        ; if so, do intermediate transfer
  1587.     bls    itrw0            ; else, go ahead with the I/O
  1588.     cmpa.l    #VA24D16,a1
  1589.     bcs.s    rw1
  1590.     cmpa.l    #VA16D16,a1
  1591.     bls    itrw0
  1592. .endif    ;SCDMA
  1593.  
  1594.     bra.s    rw1
  1595.  
  1596. rw0:    movea.l    ybuf(a6),a1        ; a1 = buffer address for r/w
  1597. rw1:    move.w    _retries,retrycnt    ; setup retry counter
  1598.  
  1599.     btst.b    #2,yrw+1(a6)        ; are retries disabled?
  1600.     beq.s    rw2            ; no, act normally
  1601.     move.w    #0,retrycnt        ; yes, so set retrycnt to zero
  1602.  
  1603. rw2:    movem.l    d1-d2/a1,-(sp)        ; preserve d1, d2 and a1
  1604.     move.w    cpun,-(sp)        ; dev.w
  1605.     move.l    a1,-(sp)        ; buf.l
  1606.     move.w    d2,-(sp)        ; count.w
  1607.     move.l    yrecno(a6),-(sp)    ; sect.L
  1608.     cmpi.l    #MAXACSECTS,d2        ; more than hr/w can handle?
  1609.     bhi.s    rw4            ; if so, use extended call (SCSI only)
  1610.     btst.b    #0,yrw+1(a6)        ; read or write?
  1611.     bne.s    rw3            ; (write)
  1612.     bsr    _hread            ; read sectors
  1613.     bra.s    rw6
  1614. rw3:    bsr    _hwrite            ; write sectors
  1615.     bra.s    rw6
  1616. rw4:    btst.b    #0,yrw+1(a6)        ; read or write?
  1617.     bne.s    rw5            ; (write)
  1618.     bsr    _xtdread        ; read sectors
  1619.     bra.s    rw6
  1620. rw5:    bsr    _xtdwrt            ; write sectors
  1621. rw6:    adda    #12,sp            ; (cleanup stack)
  1622.     movem.l    (sp)+,d1-d2/a1        ; restore d1, d2 and a1
  1623.     tst.l    d0            ; errors?
  1624.     beq    rwf            ; no error --> successful
  1625.     bmi.s    rw9            ; timed out --> retry
  1626.  
  1627.     movem.l    d1-d2/a1,-(sp)        ; preserve d1, d2 and a1
  1628.     bsr    errcode            ; find error code
  1629.     movem.l    (sp)+,d1-d2/a1        ; restore d1, d2 and a1
  1630.  
  1631.     cmpi.b    #MDMCHGD,d0        ; media change detected?
  1632.     bne.s    rw7            ; if not, fine
  1633.                     ; else record media may be changed
  1634.     move.b    #1,d0            ; d0.b = 1 (may be changed)
  1635.     bsr    s_mc_xst        ; set mcflgs and xst flags for all dev
  1636.  
  1637.     btst.b    #1,yrw+1(a6)        ; ignore media change?
  1638.     bne    rw2            ; if so, retry operation
  1639.     move.l    #E_CHNG,d0        ; else return media change
  1640.     bra    rwr
  1641.     
  1642. rw7:    cmpi.b    #WRTPRTD,d0        ; write on write-protected media?
  1643.     bne.s    rw8            ; if not, fine
  1644.     move.l    #EWRPRO,d0        ; else return write-protection error
  1645.     bra.s    rwa
  1646.  
  1647. rw8:    cmpi.b    #DRVNRDY,d0        ; drive not ready?
  1648.     bne.s    rw9            ; if not, fine
  1649.     move.l    #EDRVNR,d0        ; else return drive not ready
  1650.     bra.s    rwa
  1651.  
  1652. rw9:    subq.w    #1,retrycnt        ; drop retry count and retry
  1653.     bpl    rw2
  1654.  
  1655.     move.l    #EREADF,d0        ; read error code
  1656.     btst.b    #0,yrw+1(a6)        ; is it a write?
  1657.     beq.s    rwa            ; (read)
  1658.     move.l    #EWRITF,d0        ; write error code
  1659.  
  1660. rwa:    btst.b    #3,yrw+1(a6)        ; is this a physical operation?
  1661.     bne    rwr            ; if so, exit
  1662.                     ; else call critical error handler
  1663.     movem.l    d1-d2/a1,-(sp)        ; preserve d1, d2 and a1
  1664.     move.w    ydev(a6),d1        ; d1 = drive number
  1665. rwe:    bsr    critic
  1666.     movem.l    (sp)+,d1-d2/a1        ; restore d1, d2 and a1
  1667.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1668.     beq    rw2            ; if yes, go retry
  1669.     bra.s    rwr            ; else, head home
  1670.  
  1671. rwf:    lea    rw0,a0            ; exec of next r/w starts at rw1
  1672.     cmpa.l    ybuf(a6),a1        ; was alternate buffer used?
  1673.     beq.s    rw10            ; if not, go on to next r/w
  1674.                     ; else take care of transfer
  1675.     lea    itrw3,a0        ; exec of next r/w starts at itrw3
  1676.     btst.b    #0,yrw+1(a6)        ; was it a write?
  1677.     bne.s    rw10            ; if it was, go on to next write
  1678.                     ; else move data to supplied buffer
  1679.     move.l    a1,-(sp)        ; save address of alternate buffer
  1680.     movea.l    a1,a2            ; a2 = address of alternate buffer
  1681.     movea.l    ybuf(a6),a1        ; a1 = address of supplied buffer
  1682.     move.w    d2,d0            ; d0 = # of sectors to move
  1683.     bsr    smove            ; move data from alt buf to sup buf
  1684.     move.l    (sp)+,a1        ; restore address of alternate buffer
  1685.  
  1686. rw10:    sub.l    d2,ycount(a6)        ; ycount(a6) = # sects left to be done
  1687.     beq.s    rwd            ; if no more left, done
  1688.                     ; else get ready for next r/w
  1689.     add.l    d2,yrecno(a6)        ; yrecno(a6) = next starting sector
  1690.     move.l    d2,d0            ; d0 = # bytes done
  1691.     asl.l    #8,d0            ;    = # sectors done * 512
  1692.     add.l    d0,d0            ; 
  1693.     add.l    d0,ybuf(a6)        ; buf += (sectors_done * sector size)
  1694.     cmp.l    ycount(a6),d2        ; amount to r/w > amount doable?
  1695.     bls.s    rw11            ; if so, r/w amount doable
  1696.     move.l    ycount(a6),d2        ; else r/w all of it
  1697. rw11:    jmp    (a0)            ; go on to next r/w
  1698.  
  1699. rwd:    moveq    #0,d0            ; got here with no errors!
  1700. rwr:    unlk    a6            ; head home
  1701.     rts
  1702.  
  1703.  
  1704. ;
  1705. ;+
  1706. ; Check for media change on hard disk
  1707. ; Synopsis:    _sasi_mediach(dev)
  1708. ;        WORD dev;        4(sp).w
  1709. ;
  1710. ; Returns:    0L - media definitely has not changed
  1711. ;        1L - media _may_ have changed
  1712. ;        2L - media definitely has changed
  1713. ;
  1714. ; Uses:        d0, d1, a0, a1
  1715. ;
  1716. ; Comments:
  1717. ; Apr-4-1989    ml.    Add in grace period between _sasi_mediach()s.
  1718. ;            If _sasi_mediach() was called less than 1 s
  1719. ;            (200 _hz_200 clock ticks) ago, and medium was 
  1720. ;            not changed then, assume medium still has not 
  1721. ;            changed.
  1722. ;-
  1723. _sasi_mediach:
  1724.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  1725.     move.w    4(sp),d1        ; d1 = current drive
  1726.     lea    mcflgs,a0        ; a0 = pointer to mcflgs
  1727.     moveq    #0,d0            ; d0 = mcflg for current drive
  1728.     move.b    (a0,d1.w),d0    
  1729.     tst.b    d0            ; has medium changed?
  1730.     bne.s    decided            ; if yes or maybe, return result
  1731.                     ; else verify that it has not
  1732.     move.l    lastmdctm,d2        ; time media change was last called
  1733.     cmp.l    _hz_200,d2        ; while (_hz_200 <= lastmdctm)
  1734.     bcc.s    decided            ;    assume medium not changed
  1735.  
  1736.     lea    pun,a1            ; ptr to beginning of pun table
  1737.     move.b    (a1,d1.w),cpun+1    ; cpun = pun current drive belongs to
  1738.  
  1739.     btst.b    #6,cpun+1        ; is pun removable?
  1740.     beq.s    notchngd        ; if not, medium has not changed
  1741.  
  1742.     move.w    cpun,-(sp)        ; physical unit number
  1743.     bsr    _untrdy            ; verify by doing test unit ready
  1744.     addq.l    #2,sp
  1745.     move.l    _hz_200,lastmdctm    ; update time for last _sasi_mediach()
  1746.     addi.l    #200,lastmdctm        ; 
  1747.     tst.w    d0            ; return good status?
  1748.     beq.s    notchngd        ; if yes, return medium not changed
  1749.     moveq    #1,d0            ; else return medium may have changed
  1750.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  1751.     bra.s    decided
  1752. notchngd:
  1753.     moveq    #0,d0            ; return medium has not changed
  1754. decided:
  1755.     rts
  1756.  
  1757.  
  1758. ;+
  1759. ; s_mc_xst - set mcflgs and drive existence flags 
  1760. ;         for drives belonging to the current
  1761. ;         physical unit to value passed
  1762. ;
  1763. ; Passed:    d0.b - value to set to
  1764. ;-
  1765. s_mc_xst:
  1766.     movem.l    d1-d2/a0-a2,-(sp) ; save registers
  1767.     lea    pun,a0        ; a0 -> pun table
  1768.     lea    mcflgs,a1    ; a1 -> mcflgs table
  1769.     lea    xst,a2        ; a2 -> drive existence table
  1770.     move.w    cpun,d1        ; d1 = current physical unit #
  1771.     moveq    #0,d2        ; d2 = logical drive #; index into tables
  1772. set0:    btst.b    #7,(a0,d2.w)    ; a valid logical drive?
  1773.     bne.s    setr        ; if not, done
  1774.     cmp.b    (a0,d2.w),d1    ; else, does it belong to this physical unit?
  1775.     bne.s    set1        ; if not, move on to next logical drive
  1776.     move.b    d0,(a1,d2.w)    ; else change its mcflg to value passed
  1777.     move.b    d0,(a2,d2.w)    ; and change its xst to value passed
  1778. set1:    addq.w    #1,d2        ; try next one in forward direction
  1779.     cmp.w    #MAXUNITS,d2    ; all units checked?
  1780.     blt.s    set0        ; if not, go on
  1781. setr:    movem.l    (sp)+,d1-d2/a0-a2 ; else restore registers
  1782.     rts            ; and return
  1783.  
  1784.  
  1785. ;
  1786. ;+
  1787. ; Resident Installer
  1788. ;-
  1789.     .globl    i_sasi6
  1790. i_sasi6:
  1791. ;+
  1792. ; 02-Apr-1991    ml.    The following is illegal, because i_sasi1 is 
  1793. ;            external.
  1794. ;    move.l    #(i_sasi1-i_sasi),tokeep ; at least keep this much
  1795. ;-
  1796.     move.l    #i_sasi1,tokeep ; tokeep = amount of code to be kept
  1797.     subi.l    #i_sasi,tokeep
  1798.     cmpi.w    #512,maxssz    ; maxssz > 512 bytes?
  1799.     bls.s    nboot1        ; if not, don't need to replace GEMDOS buffers
  1800.                 ; else check if there is enough memory for
  1801. chkmem:    bsr    chklstmem    ;   new GEMDOS buffer lists
  1802.     tst.l    d0        ; enough?
  1803.     bpl.s    okbig        ; if so, build the list
  1804.     move.w    defbigsect,d0    ; d0 = minimum big sector
  1805.     cmp.w    maxssz,d0    ; is maxssz >= minimum big sector?
  1806.     bcc.s    regsect        ; if so, give up
  1807.     move.w    d0,maxssz    ; else try minimum big sector
  1808.     bra.s    chkmem
  1809. regsect:
  1810.     move.w    #512,maxssz    ; will not handle big sectors
  1811.     bra.s    nboot1
  1812.  
  1813. okbig:    move.l    d1,tokeep    ; update amount of memory to be kept
  1814.     lea    i_sasi1,a0    ; a0 -> beginning of new buffer lists
  1815.     moveq    #3,d1        ; d1 = count = 4 buffers - 1
  1816.     bsr    list_init    ; initialize the buffer list
  1817.     clr.l    (a0,d0.w)    ; cut 1 list of 4 buffers to 2 lists of 2
  1818.     move.l    a0,_bufl    ; _bufl[0] -> 1st new buffer list
  1819.     add.l    d0,d0        ; d0 = offset to beginning of 2nd buffer list
  1820.     adda.l    d0,a0        ; a0 = head of 2nd buffer list
  1821.     move.l  a0,_bufl+4    ; _bufl[1] -> 2nd new buffer list
  1822.  
  1823. nboot1:    bsr    pool_install    ; attempt to install more OS pool
  1824.     add.l    d0,tokeep    ; update amount of memory to be kept
  1825.  
  1826. ;    clr.l    frbbuf        ; assume no _FRB
  1827. ;    move.l    #frbbuf,-(sp)    ; pointer to fast RAM buffer
  1828. ;    move.l    #$5f465242,-(sp)    ; cookie "_FRB"
  1829. ;    bsr    _getcookie    ; try to find _FRB in cookie jar
  1830. ;    addq.w    #8,sp        ; clean up stack
  1831.  
  1832.     move.l    _hz_200,lastmdctm    ; initialize media change time
  1833.     tst.w    bootloaded    ; if bootloaded, then already in super mode
  1834.     bne.s    nboot2        ; (already there)
  1835.     move.l    savssp,-(sp)    ; become a mild mannered user process
  1836.     move.w    #$20,-(sp)    ; Super(savssp)
  1837.     trap    #1
  1838.     addq.w    #6,sp
  1839.  
  1840. ;+
  1841. ; Terminate and stay resident;
  1842. ; installed driver under GEMDOS.
  1843. ;-
  1844.     move.l    tokeep,d0    ; compute value for Ptermres()
  1845.     add.l    #$0100,d0    ; for basepage
  1846.     move.l    d0,-(sp)    ; save D0
  1847.     pea    msg_nbl(pc)    ; print announcement
  1848.     move.w    #9,-(sp)
  1849.     trap    #1
  1850.     addq.l    #6,sp
  1851.     move.l    (sp)+,d0
  1852.     move.w    #0,-(sp)    ; exit code
  1853.     move.l    d0,-(sp)
  1854.     move.w    #$31,-(sp)    ; terminate and stay resident
  1855.     trap    #1        ; should never come back...
  1856.     illegal
  1857.  
  1858.  
  1859. ;+
  1860. ;  Return to TOS ROMs
  1861. ;    - set default boot device to C:
  1862. ;    - Print silly message
  1863. ;    - Mshrink() memory that was alloc'd to us
  1864. ;    - set magic# in D7 for TOS ROMs
  1865. ;    - RTS back to ROMs
  1866. ;-
  1867. nboot2:    move.l    tokeep,d0    ; compute value for Mshrink
  1868.     add.l    #$1c,d0        ; for file header
  1869.     move.l    d0,-(sp)    ; save D0
  1870.     pea    msg_bl(pc)    ; print announcement
  1871.     move.w    #9,-(sp)
  1872.     trap    #1
  1873.     addq.l    #6,sp        ; clean up stack
  1874.  
  1875.     move.w    d4,d1        ; physical unit # in d4.w?
  1876.     bpl.s    bd0        ; if so, good
  1877.                 ; else it's in hi 3 bits of d7.b
  1878.     move.b    d7,d1        ; d1.b = physical unit # boot loaded from
  1879.     lsr.b    #5,d1        ;      = xxx00000 >> 5
  1880. bd0:    lea    pun,a0        ; a0 -> pun table
  1881.     moveq    #0,d2        ; d2 = boot dev
  1882. bd1:    move.b    (a0,d2.w),d0    ; d0.b = unit #
  1883.     andi.b    #$0f,d0        ; mask out flags
  1884.     cmp.b    d0,d1        ; d2 belongs to physical unit booted from?
  1885.     beq.s    bd2        ; if yes, set (d2) as boot device
  1886.     addq.w    #1,d2        ; else try next logical unit
  1887.     bra.s    bd1
  1888. bd2:    addq.w    #2,d2        ; offset for drive A and B
  1889.     move.w    d2,_bootdev    ; set default boot device to (d2)
  1890.  
  1891.     move.l    baseaddr,-(sp)
  1892.     clr.w    -(sp)
  1893.     move.w    #$4a,-(sp)    ; Mshrink(...)
  1894.     trap    #1
  1895.     adda    #12,sp        ; (cleanup stack)
  1896.  
  1897.     move.w    _bootdev,-(sp)    ; set boot dev as default drive
  1898.     move.w    #$e,-(sp)    ; Dsetdrv(_bootdev)
  1899.     trap    #1
  1900.     addq.w    #4,sp        ; cleanup stack
  1901.  
  1902.     move.l    #rootpath,-(sp)    ; set root as current directory
  1903.     move.w    #$3b,-(sp)    ; Dsetpath('\')
  1904.     trap    #1
  1905.     addq.w    #6,sp        ; cleanup stack
  1906. ;
  1907. ;    move.l    _sysbase,a0    ; get the system header address
  1908. ;    move.l    $18(a0),d0    ; d0.l = MMDDYYYY of ROM date
  1909. ;    swap    d0        ; d0.l = YYYYMMDD of ROM date
  1910. ;    cmp.l    #CHKDATE,d0    ; does this version of ROM need bootstop?
  1911. ;    bcs.s    stopall        ; yup, if OS is built before 4/22/87
  1912. ;    move.b    puns+1,d7    ; else prevent processed units from booting
  1913. ;    subq.b    #1,d7        ; unit # = # of units - 1
  1914. ;    lsl.b    #5,d7
  1915. ;    rts            ; return to TOS ROMs
  1916. ;
  1917. ; Stop ANY subsequent boot after the hard disk boot -- FOR NOW!!
  1918. ;
  1919.  
  1920. stopall:
  1921.     move.b    #$100-$20,d7    ; prevent any other unit from booting
  1922.     rts            ; return to TOS ROMs
  1923.  
  1924. rootpath:
  1925.     dc.b    '\\',0
  1926. msg_bl:
  1927.     dc.b    'BOOTLOADED',13,10,0
  1928. msg_nbl:
  1929.     dc.b    'NOT Bootloaded',13,10,0
  1930. .even
  1931.  
  1932.  
  1933. ;+
  1934. ; list_init - Initialize a GEMDOS buffer list (BCBs are contiguous)
  1935. ;
  1936. ; Passed:
  1937. ;     a0.l = head of buffer list            (not changed)
  1938. ;    d0.l = size of each BCB (including data block)    (not changed)
  1939. ;    d1.w = count
  1940. ;         = number of buffers to be installed to the list - 1
  1941. ;
  1942. ; Uses:
  1943. ;    d1, a1
  1944. ;-
  1945. list_init:
  1946.     move.l    a0,-(sp)    ; save head of buffer list
  1947. lin0:    movea.l    a0,a1        ; a1 -> next BCB
  1948.     adda.l    d0,a1        ;    -> curr BCB + size of BCB
  1949.     move.l    a1,(a0)        ; b_link -> next BCB
  1950.     move.w    #-1,4(a0)    ; b_neg1 = -1
  1951.     adda.w    #BCBLEN,a0    ; a0 -> BCB data block
  1952.     move.l    a0,-4(a0)    ; b_bufr -> b_space
  1953.     movea.l    a1,a0
  1954.     dbra    d1,lin0
  1955.     suba.l    d0,a0        ; a0 -> last BCB
  1956.     clr.l    (a0)        ; lastBCB.b_link = NULL
  1957.     move.l    (sp)+,a0    ; restore head of buffer list
  1958.     rts
  1959.  
  1960.  
  1961. ;+
  1962. ; chklstmem - check if enough memory is allocated to replace GEMDOS
  1963. ;        buffer lists
  1964. ;
  1965. ; Returns:
  1966. ;    d0.l = size of each BCB (including data block)
  1967. ;         or -1 if not enough memory is allocated
  1968. ;    d1.l = new amount of memory to be kept if enough is allocated
  1969. ;
  1970. ; Uses:
  1971. ;    d0, d1
  1972. ;-
  1973. chklstmem:
  1974.     moveq    #BCBLEN,d0    ; d0.l = size of each BCB (inc. data block)
  1975.     add.w    maxssz,d0    ;      = BCB header len + data block size
  1976.     move.l    d0,d1        ; d1.l = d0.l * 4 
  1977.     lsl.l    #2,d1        ;      = total size of buffer lists
  1978.     add.l    tokeep,d1    ; d1.l = size needed
  1979.     cmp.l    memalloc,d1    ; enough memory allocated?
  1980.     bls.s    chk0        ; if so return
  1981.     moveq    #-1,d0        ; else return error
  1982. chk0:    rts
  1983.  
  1984.  
  1985. ;
  1986. ;+
  1987. ; critic - call up the critical error handler.
  1988. ;
  1989. ; Passed:
  1990. ;    d0.w = error code
  1991. ;    d1.w = drive # excluding A: and B:
  1992. ;
  1993. ; Uses:
  1994. ;    d0, d1, a0
  1995. ;
  1996. ; Returns:
  1997. ;    d0.l = whatever returned by the critical handler
  1998. ;        (magic RETRY code or something)
  1999. ;-
  2000. critic:    addq.w    #2,d1            ; drive # including A: and B:
  2001.     move.w    d1,-(sp)        ; drive #
  2002.     move.w    d0,-(sp)        ; error code
  2003.     movea.l    etv_critic,a0        ; a0 = address of error handler
  2004.     jsr    (a0)            ; critic_handler(error, drive)
  2005.     addq.l    #4,sp            ; clean up stack
  2006.     rts                ; return
  2007.  
  2008.  
  2009. ;+
  2010. ; errcode - find error code for previous Check Condition Status
  2011. ;
  2012. ; Assumed:
  2013. ;    cpun = current physical unit number
  2014. ;
  2015. ; Returns:
  2016. ;    d0.b = error code    (aka additional sense code)
  2017. ;
  2018. ; Sep-13-1989    ml.    For non-extended request sense, ask for 0 byte.
  2019. ;            (0 is default to return 4 bytes.)
  2020. ;-
  2021.     .globl    errcode
  2022. errcode:
  2023.     moveq    #22,d1            ; assume requesting extended sense
  2024.     move.w    cpun,d0            ; d0 = physical unit number
  2025.     btst    #3,d0            ; a SCSI unit?
  2026.     bne.s    err0            ; if so, ready to request
  2027.     andi.w    #07,d0            ; else mask off other flags
  2028.     btst.b    d0,embscsi        ; an embedded SCSI unit using ACSI?
  2029.     bne.s    err0            ; if so, request extended sense
  2030.     moveq    #0,d1            ; else request non-extended sense
  2031. err0:    lea    sendata,a0        ; a0 -> sense data buffer
  2032.     movem.l    d1/a0,-(sp)        ; save data len and buffer address
  2033.     move.l    a0,-(sp)        ; sense data buffer
  2034.     move.w    d1,-(sp)        ; data length (in bytes)
  2035.     move.w    d0,-(sp)        ; physical unit number
  2036.     bsr    _rqsense        ; find out error code
  2037.     addq.l    #8,sp            ; clean up stack
  2038.     movem.l    (sp)+,d1/a0        ; restore d1 and a0
  2039.     tst.w    d0            ; successful?
  2040.     beq.s    err1            ; if not, return
  2041.     moveq    #-1,d0            ; error occurred
  2042.     rts
  2043. err1:    cmpi.w    #4,d1            ; extended or non-extended?
  2044.     bgt.s    err2            ; if extended, go get code
  2045.     move.b    (a0),d0            ; else byte 0 = error code
  2046.     andi.b    #$7f,d0            ; mask off valid bit
  2047.     rts
  2048. err2:    move.b    12(a0),d0        ; else byte 12 = error code
  2049.     rts
  2050.  
  2051.  
  2052. ;
  2053. ;+
  2054. ; OS Pool Expansion
  2055. ;-
  2056.  
  2057. .if ospool
  2058. ;+
  2059. ;  Wire more pool into various ROM releases.
  2060. ;
  2061. ;    Passed:    nothing
  2062. ;    Returns:    D0 = #bytes extra used
  2063. ;-
  2064. pool_install:
  2065.     move.l    _sysbase,a3        ; a3 -> base of OS
  2066.  
  2067. ; make sure we're in ROM,
  2068. ; then get address of RAM location to patch:
  2069.  
  2070.     cmp.l    #$800000,a3        ; better be ROM
  2071.     blt    notrom
  2072.     lea    pool_tab(pc),a0        ; a0 -> table to match
  2073. pi_lp:    move.l    (a0)+,d1        ; d1 = date to match
  2074.     beq    badrom            ; (forget it, end of list)
  2075.     move.l    (a0)+,a2        ; a2 -> _root address for that date
  2076.     cmp.l    $18(a3),d1        ; match dates?
  2077.     bne.s    pi_lp            ; (no -- try again)
  2078.  
  2079.     move.w    numchunks,d0        ; d0 = amount of BSS to be used
  2080.     mulu    #chunksiz,d0        ;    = # chunks * size of a chunk
  2081.     move.l    d0,d1            ; d1 = total memory needed
  2082.     add.l    tokeep,d1        ;    = already keeping + extra OS pool
  2083.     cmp.l    memalloc,d1        ; enough is allocated?
  2084.     bgt.s    bdrom2            ; if not, don't add any
  2085.                     ; else install more OS pool
  2086.     movea.l    #i_sasi+2,a0        ; a0 -> base of first buffer
  2087.     adda.l    tokeep,a0        ;    = start of file + already keeping
  2088.     move.l    a0,-(sp)        ; save base of first buffer
  2089.     move.w    numchunks,d1        ; d0 = count-1
  2090.     subq.w    #1,d1
  2091. pin_1:    lea    chunksiz(a0),a1        ; a1 -> next buffer
  2092.     move.l    a1,(a0)            ; buffer -> next one
  2093.     move.w    #chunkno,-2(a0)        ; install chunksiz
  2094.     move.l    a1,a0            ; a0 -> next buffer
  2095.     dbra    d1,pin_1        ; (do some more)
  2096.  
  2097.     sub.w    #chunksiz,a0        ; a0 -> last block
  2098.     move.l    chunkno*4(a2),(a0)    ; last block -> first in root
  2099.     move.l    (sp)+,chunkno*4(a2)     ; root -> first of ours
  2100.     rts                ; return OK
  2101.  
  2102. ;+
  2103. ;  Print warning messages
  2104. ;  about bogus versions of the
  2105. ;  operating system.  Assume that
  2106. ;  every OS past 1-May-1986 has the
  2107. ;  pool fix installed.
  2108. ;
  2109. ;-
  2110. ok_date    =    %0000110010100001    ; 1-May-1986
  2111. notrom:    lea    m_notrom(pc),a0        ; ram-based system (5/29!)
  2112.     bra.s    bdrom1
  2113. badrom:    lea    m_badrom(pc),a0        ; illegal ROM system
  2114. bdrom1:    cmp.w    #ok_date,$1e(a3)    ; if ok_date <= os_dosdate(a3) 
  2115.     bcc    bdrom2            ; then don't print anything
  2116.  
  2117.     move.l    a0,-(sp)        ; print nasty message
  2118.     move.w    #9,-(sp)
  2119.     trap    #1
  2120.     addq.l    #6,sp
  2121.  
  2122. ; print msg and wait for RETURN
  2123.     pea    keymsg(pc)
  2124.     move.w    #9,-(sp)
  2125.     trap    #1
  2126.     addq.l    #6,sp
  2127.  
  2128. bdrom3:    move.w    #2,-(sp)        ; wait for [RETURN]
  2129.     move.w    #2,-(sp)
  2130.     trap    #13
  2131.     addq.l    #4,sp
  2132.     cmp.w    #13,d0
  2133.     bne    bdrom3
  2134.  
  2135. bdrom2:    moveq    #0,d0            ; 0 extra bytes used
  2136.     rts
  2137.  
  2138. keymsg:    dc.b    'Hard disk driver not loaded; hit RETURN',13,10
  2139.     dc.b    'key to continue:',13,10
  2140.     dc.b    0
  2141.  
  2142. m_notrom:
  2143.     dc.b    '*** WARNING ***',13,10,7
  2144.     dc.b    'This hard disk driver may not work with',13,10,7
  2145.     dc.b    'a disk-based version of TOS; files on',13,10,7
  2146.     dc.b    'your hard disk may be damaged.',13,10,7
  2147.     dc.b    13,10,7
  2148.     dc.b    0
  2149.  
  2150. m_badrom:
  2151.     dc.b    '*** WARNING ***',13,10,7
  2152.     dc.b    'You are using an unofficial ROM release',13,10,7
  2153.     dc.b    'of the operating system.  This driver',13,10,7
  2154.     dc.b    'may not work correctly with it.  Files',13,10,7
  2155.     dc.b    'on your hard disk may be damaged.',13,10,7
  2156.     dc.b    13,10,7
  2157.     dc.b    0
  2158.     even
  2159.  
  2160.  
  2161. ;+
  2162. ;  Table of ROM release dates / _root addresses
  2163. ;  update these for new ROM releases that need the patch.
  2164. ;
  2165. ;-
  2166. pool_tab:
  2167.     dc.l    $11201985,$56fa        ; USA and UK, 20-Nov-1985
  2168.     dc.l    $02061986,$56fa        ; Germany, 6-Feb-1986
  2169.     dc.l    $04241986,$56fa        ; France, 24-Apr-1986
  2170.     dc.l    0            ; end of list
  2171.  
  2172. .endif
  2173.  
  2174.  
  2175.